Hi,
I’m finalizing my Vulkan game engine.
Inside my game engine, I highly rely on push constants to pass some light-weight constants to GPU pipeline, like:
struct PushConstants //sizeof is 128 bytes, reached the limits
{
// ---------- data for 2D and 3D ----------
float colorConst[4]; //0
bool32_t textureEnabled; //4
bool32_t alphaTestEnabled; //5
bool32_t texcoordTransformationEnabled; //6
bool32_t imageByLuminance; //7
// ---------- data for 3D only ----------
bool32_t shadingEnabled; //8
bool32_t fogEnabled; //9
float fogStart; //10
float fogEnd; //11
float fogColor[3]; //12 (Note: alignment!)
bool32_t flatShading; //15
bool32_t specularEnabled; //16
bool32_t generateReflectionTexCoord; //17
uint32_t mtlSpecularPower; //18
float zBias; //19
float mtlDiffuse[4]; //20 (Note: alignment!)
float mtlEmissive[4]; //24 (Note: alignment!)
float mtlSpecular[4]; //28 (Note: alignment!)
};
During the rendering of 2D / 3D scenes, I update push constants many times to pass in attributes of each 2D / 3D objects. So the commands recorded on command buffers looks like:
vkCmdBeginRenderPass(...)
vkCmdPushConstants(...)
vkCmdBindDescriptorSets(...)
vkCmdDraw...(...)
vkCmdPushConstants(...)
vkCmdBindDescriptorSets(...)
vkCmdDraw...(...)
vkCmdPushConstants(...)
vkCmdBindDescriptorSets(...)
vkCmdDraw...(...)
...
vkCmdEndRenderPass(...)
This works well on all Vulkan platforms (nVidia, AMD, Intel, Adreno, Mali, Apple Metal) except PowerVR (My testing device is Acer Iconia 7 with PowerVR GE8300 GPU). Some push constants such as colorConst seem to be messed up between vkCmdDraw(…) calls
For example, If I have code like:
vkCmdPushConstants(...); //Pass in colorConst as RED
vkCmdDraw(...); //Draw a rectangle
vkCmdPushConstants(...); //Pass in colorConst as BLUE
vkCmdDraw(...); //Draw a triangle
The intention of above code is to draw a RED rectangle first, then draw a BLUE triangle. The actual result may be both shape are drawn in RED, and the result can be unpredictable.
I allocate a 128-bytes data block at CPU side and I update its content right before I call vkCmdPushConstants(). So the data block at CPU side is reused:
vkCmdPushConstants(pCommandBuf, vkPipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(pushConstants), &pushConstants);
As far as I know, when Vulkan function vkCmdPushConstants(…) is called, the content of the data block (up to 128 bytes) are copied into GPU pipeline and therefore I can freely update the data right away for the next drawing command. There is no synchronization required by Vulkan specification.
My question, does PowerVR series GPU have extra requirement or steps when sending in push constants to the Gpu pipeline, like sort of synchronization?
Thanks for any suggestions.