Panda3D
shaderBuffer.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file shaderBuffer.cxx
10  * @author rdb
11  * @date 2016-12-12
12  */
13 
14 #include "shaderBuffer.h"
16 
17 TypeHandle ShaderBuffer::_type_handle;
18 
19 /**
20  * Destructor.
21  */
24  release_all();
25 }
26 
27 /**
28  *
29  */
30 void ShaderBuffer::
31 output(std::ostream &out) const {
32  out << "buffer " << get_name() << ", " << _data_size_bytes << "B, " << _usage_hint;
33 }
34 
35 /**
36  * Indicates that the data should be enqueued to be prepared in the indicated
37  * prepared_objects at the beginning of the next frame. This will ensure the
38  * data is already loaded into the GSG if it is expected to be rendered soon.
39  *
40  * Use this function instead of prepare_now() to preload datas from a user
41  * interface standpoint.
42  */
43 void ShaderBuffer::
44 prepare(PreparedGraphicsObjects *prepared_objects) {
45  prepared_objects->enqueue_shader_buffer(this);
46 }
47 
48 /**
49  * Returns true if the data has already been prepared or enqueued for
50  * preparation on the indicated GSG, false otherwise.
51  */
52 bool ShaderBuffer::
53 is_prepared(PreparedGraphicsObjects *prepared_objects) const {
54  if (_contexts == nullptr) {
55  return false;
56  }
57  Contexts::const_iterator ci;
58  ci = _contexts->find(prepared_objects);
59  if (ci != _contexts->end()) {
60  return true;
61  }
62  return prepared_objects->is_shader_buffer_queued(this);
63 }
64 
65 /**
66  * Creates a context for the data on the particular GSG, if it does not
67  * already exist. Returns the new (or old) BufferContext. This assumes
68  * that the GraphicsStateGuardian is the currently active rendering context
69  * and that it is ready to accept new datas. If this is not necessarily the
70  * case, you should use prepare() instead.
71  *
72  * Normally, this is not called directly except by the GraphicsStateGuardian;
73  * a data does not need to be explicitly prepared by the user before it may be
74  * rendered.
75  */
79  if (_contexts == nullptr) {
80  _contexts = new Contexts;
81  }
82  Contexts::const_iterator ci;
83  ci = _contexts->find(prepared_objects);
84  if (ci != _contexts->end()) {
85  return (*ci).second;
86  }
87 
88  BufferContext *vbc = prepared_objects->prepare_shader_buffer_now(this, gsg);
89  if (vbc != nullptr) {
90  (*_contexts)[prepared_objects] = vbc;
91  }
92  return vbc;
93 }
94 
95 /**
96  * Frees the data context only on the indicated object, if it exists there.
97  * Returns true if it was released, false if it had not been prepared.
98  */
99 bool ShaderBuffer::
100 release(PreparedGraphicsObjects *prepared_objects) {
101  if (_contexts != nullptr) {
102  Contexts::iterator ci;
103  ci = _contexts->find(prepared_objects);
104  if (ci != _contexts->end()) {
105  BufferContext *vbc = (*ci).second;
106  prepared_objects->release_shader_buffer(vbc);
107  return true;
108  }
109  }
110 
111  // Maybe it wasn't prepared yet, but it's about to be.
112  return prepared_objects->dequeue_shader_buffer(this);
113 }
114 
115 /**
116  * Frees the context allocated on all objects for which the data has been
117  * declared. Returns the number of contexts which have been freed.
118  */
119 int ShaderBuffer::
121  int num_freed = 0;
122 
123  if (_contexts != nullptr) {
124  // We have to traverse a copy of the _contexts list, because the
125  // PreparedGraphicsObjects object will call clear_prepared() in response
126  // to each release_shader_buffer(), and we don't want to be modifying the
127  // _contexts list while we're traversing it.
128  Contexts temp = *_contexts;
129  num_freed = (int)_contexts->size();
130 
131  Contexts::const_iterator ci;
132  for (ci = temp.begin(); ci != temp.end(); ++ci) {
133  PreparedGraphicsObjects *prepared_objects = (*ci).first;
134  BufferContext *vbc = (*ci).second;
135  prepared_objects->release_shader_buffer(vbc);
136  }
137 
138  // Now that we've called release_shader_buffer() on every known context,
139  // the _contexts list should have completely emptied itself.
140  nassertr(_contexts == nullptr, num_freed);
141  }
142 
143  return num_freed;
144 }
145 
146 /**
147  * Removes the indicated PreparedGraphicsObjects table from the buffer's
148  * table, without actually releasing the texture. This is intended to be
149  * called only from PreparedGraphicsObjects::release_shader_buffer(); it
150  * should never be called by user code.
151  */
152 void ShaderBuffer::
153 clear_prepared(PreparedGraphicsObjects *prepared_objects) {
154  nassertv(_contexts != nullptr);
155 
156  Contexts::iterator ci;
157  ci = _contexts->find(prepared_objects);
158  if (ci != _contexts->end()) {
159  _contexts->erase(ci);
160  if (_contexts->empty()) {
161  delete _contexts;
162  _contexts = nullptr;
163  }
164  } else {
165  // If this assertion fails, clear_prepared() was given a prepared_objects
166  // which the data array didn't know about.
167  nassert_raise("unknown PreparedGraphicsObjects");
168  }
169 }
170 
171 /**
172  * Tells the BamReader how to create objects of type ParamValue.
173  */
174 void ShaderBuffer::
176  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
177 }
178 
179 /**
180  * Writes the contents of this object to the datagram for shipping out to a
181  * Bam file.
182  */
183 void ShaderBuffer::
185  dg.add_string(get_name());
186  dg.add_uint64(_data_size_bytes);
187  dg.add_uint8(_usage_hint);
188  dg.add_bool(!_initial_data.empty());
189  dg.append_data(_initial_data.data(), _initial_data.size());
190 }
191 
192 /**
193  * This function is called by the BamReader's factory when a new object of
194  * type ParamValue is encountered in the Bam file. It should create the
195  * ParamValue and extract its information from the file.
196  */
197 TypedWritable *ShaderBuffer::
198 make_from_bam(const FactoryParams &params) {
199  ShaderBuffer *param = new ShaderBuffer;
200  DatagramIterator scan;
201  BamReader *manager;
202 
203  parse_params(params, scan, manager);
204  param->fillin(scan, manager);
205 
206  return param;
207 }
208 
209 /**
210  * This internal function is called by make_from_bam to read in all of the
211  * relevant data from the BamFile for the new ParamValue.
212  */
213 void ShaderBuffer::
214 fillin(DatagramIterator &scan, BamReader *manager) {
215  set_name(scan.get_string());
216  _data_size_bytes = scan.get_uint64();
217  _usage_hint = (UsageHint)scan.get_uint8();
218 
219  if (scan.get_bool() && _data_size_bytes > 0) {
220  nassertv_always(_data_size_bytes <= scan.get_remaining_size());
221  _initial_data.resize((_data_size_bytes + 15u) & ~15u);
222  scan.extract_bytes(&_initial_data[0], _data_size_bytes);
223  } else {
224  _initial_data.clear();
225  }
226 }
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the data context only on the indicated object, if it exists there.
This is our own Panda specialization on the default STL map.
Definition: pmap.h:49
const std::string & get_name() const
Returns the name of the PreparedGraphicsObjects structure.
bool get_bool()
Extracts a boolean value.
uint64_t get_uint64()
Extracts an unsigned 64-bit integer.
This is a generic buffer object that lives in graphics memory.
Definition: shaderBuffer.h:33
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
void release_shader_buffer(BufferContext *bc)
Indicates that a data context, created by a previous call to prepare_shader_buffer(),...
bool is_shader_buffer_queued(const ShaderBuffer *data) const
Returns true if the index buffer has been queued on this GSG, false otherwise.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void append_data(const void *data, size_t size)
Appends some more raw data to the end of the datagram.
Definition: datagram.cxx:129
This is the fundamental interface for extracting binary objects from a Bam file, as generated by a Ba...
Definition: bamReader.h:110
This is a base class for those kinds of SavedContexts that occupy an easily-measured (and substantial...
Definition: bufferContext.h:38
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
static void register_with_read_factory()
Tells the BamReader how to create objects of type ParamValue.
This is the fundamental interface for writing binary objects to a Bam file, to be extracted later by ...
Definition: bamWriter.h:63
A table of objects that are saved within the graphics context for reference by handle later.
size_t get_remaining_size() const
Return the bytes left in the datagram.
int release_all()
Frees the context allocated on all objects for which the data has been declared.
std::string get_string()
Extracts a variable-length string.
~ShaderBuffer()
Destructor.
vector_uchar extract_bytes(size_t size)
Extracts the indicated number of bytes in the datagram and returns them as a string.
void parse_params(const FactoryParams &params, DatagramIterator &scan, BamReader *&manager)
Takes in a FactoryParams, passed from a WritableFactory into any TypedWritable's make function,...
Definition: bamReader.I:275
virtual void write_datagram(BamWriter *manager, Datagram &dg)
Writes the contents of this object to the datagram for shipping out to a Bam file.
void prepare(PreparedGraphicsObjects *prepared_objects)
Indicates that the data should be enqueued to be prepared in the indicated prepared_objects at the be...
void add_bool(bool value)
Adds a boolean value to the datagram.
Definition: datagram.I:34
BufferContext * prepare_shader_buffer_now(ShaderBuffer *data, GraphicsStateGuardianBase *gsg)
Immediately creates a new BufferContext for the indicated data and returns it.
void enqueue_shader_buffer(ShaderBuffer *data)
Indicates that a buffer would like to be put on the list to be prepared when the GSG is next ready to...
void add_string(const std::string &str)
Adds a variable-length string to the datagram.
Definition: datagram.I:219
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
void register_factory(TypeHandle handle, CreateFunc *func, void *user_data=nullptr)
Registers a new kind of thing the Factory will be able to create.
Definition: factory.I:73
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const
Returns true if the data has already been prepared or enqueued for preparation on the indicated GSG,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a base class for the GraphicsStateGuardian class, which is itself a base class for the variou...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
void add_uint8(uint8_t value)
Adds an unsigned 8-bit integer to the datagram.
Definition: datagram.I:50
A class to retrieve the individual data elements previously stored in a Datagram.
BufferContext * prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the data on the particular GSG, if it does not already exist.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
void add_uint64(uint64_t value)
Adds an unsigned 64-bit integer to the datagram.
Definition: datagram.I:103
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
bool dequeue_shader_buffer(ShaderBuffer *data)
Removes a buffer from the queued list of data arrays to be prepared.