For a while I've been trying to implement correctly s struct that HOLDS all the possible data that could be needed to execute a draw call in a single struct. I tough that I invented the hot water, but it turns out that other are also doing it and form what I *hear* they are doing better. To put you in context here is what ive got
struct DrawCall
{
// Buffer Texture SamplerState ARE JUST POINTERS - LITERALLY
typedef std::vector<Pair<unsigned, Buffer>> BoundCBuffersContainter;
typedef std::vector<Pair<unsigned, Texture>> BoundTexturesContainter;
typedef std::vector<Pair<unsigned, SamplerState>> BoundSamplersContainter;
std::vector<BoundUniform> m_uniforms; // a quick access to the 0th CBuffer in D3D or the uniforms in OpenGL, holds std::string uniform name(as hashed int), type and byte offset int m_uniformdata
std::vector<char> m_uniformData;
ShadingProgram m_shadingProg; // POINTER
Buffer m_vertexBuffers[GraphicsCaps::NUM_VERTEX_BUFFER_SLOTS]; // AN ARRAY OF POINTERS, GraphicsCaps::NUM_VERTEX_BUFFER_SLOTS is ~8
uint32 m_vbOffsets[GraphicsCaps::NUM_VERTEX_BUFFER_SLOTS];
uint32 m_vbStrides[GraphicsCaps::NUM_VERTEX_BUFFER_SLOTS];
VertexDeclIndex m_vertDeclIndex;
PrimitiveTopology::Enum m_primTopology;
Buffer m_indexBuffer; // POINTER
UniformType::Enum m_indexBufferFormat;
uint32 m_indexBufferByteOffset;
BoundCBuffersContainter m_boundCbuffers; // STD::VECTOR OF POINTERS
BoundTexturesContainter m_boundTextures; // STD::VECTOR OF POINTERS
BoundSamplersContainter m_boundSamplers; // STD::VECTOR OF POINTERS
FrameTarget m_frameTarget; //POINTER (a set of render targets + depth buffer)
Viewport m_viewport;
RasterizerState m_rasterState; // POINTER
DepthStencilState m_depthStencilState; // POINTER
BlendState m_blendState; // POINTER
AABox2i m_scissorRect; // This will be used only if useScissors is true in the rasterizer state.
DrawExecDesc m_drawExec; // linear indexed ect. vertex bufffer num primitives ect.
DrawCall();
~DrawCall() = default;
// Just setter for the values above.
void setProgram(ShadingProgram pShadingProgram);
void setVB(const int slot, Buffer pBuffer, const uint32 byteOffset, const uint32 stride);
void SetVBDeclIndex(const VertexDeclIndex idx);
void setPrimitiveTopology(const PrimitiveTopology::Enum pt);
void setIB(Buffer pBuffer, const UniformType::Enum format, const uint32 byteOffset);
void setCBuffer(const unsigned nameStrIdx, Buffer cbuffer); // nameStrIdx is just a hash (actually retrieved by std::map<std::string, int>)
void setTexture(const unsigned nameStrIdx, Texture texture, const bool bindSampeler = true);// nameStrIdx is just a hash (actually retrieved by std::map<std::string, int>)
void setSampler(const unsigned nameStrIdx, SamplerState sampler);// nameStrIdx is just a hash (actually retrieved by std::map<std::string, int>)
void setFrameTarget(FrameTarget frameTarget);
void setRenderState(RasterizerState rasterState, DepthStencilState depthStencilState, BlendState blendState = BlendState());
void setScissorsRect(const AABox2i& rect);
void setViewport(const Viewport& viewport);void draw(const uint32 numVerts, const uint32 startVert, const uint32 numInstances = 1);
void drawIndexed(const uint32 numIndices, const uint32 startIndex, const uint32 startVert, const uint32 numInstances = 1);
// This functions checks the validity of the bound resources
// and returns true if the draw call is valid-ish...
// [CAUTION] this function is NOT complete.
bool validateDrawCall() const;
};
So far so good...
This struct struct could later passed to a "Context" that can execute it. My problems are:
- The struct under x64 i 400 bytes long.
- The struct allocates (via std::vector) in order to hold the bound data: A quick solution to fix this is
- use static arrays (will increase the overall size of the struct but no dynamic allocations)
- reuse a DrawCall struct when possible (which is pretty often), but this basically kill the whole idea of having DrawCall as structs
Technically that DrawCall reuse isn't that bad, but i have this gut feeling that it is not right. All suggestions are welcome.
My other issue is the way I bind resources (texture, constant buffers, sampler states, "regular uniforms"(I use that because they are WAY easier than constant buffer).
Also I like the idea of binding something by string-name/string-hash but that lookup is a bit costly, so I think something like slots as in d3d might be better, any suggestions here?
So any suggestions how i can improve that?