mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-07-10 07:05:54 +00:00
OpenGL: Fix push constants disappearing on pipeline change
This commit is contained in:
parent
3ef4121d4e
commit
a214b7f12d
@ -29,6 +29,69 @@
|
|||||||
namespace backend {
|
namespace backend {
|
||||||
namespace opengl {
|
namespace opengl {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
// Push constants are implemented using OpenGL uniforms, however they aren't part of the global
|
||||||
|
// OpenGL state but are part of the program state instead. This means that we have to reapply
|
||||||
|
// push constants on pipeline change.
|
||||||
|
//
|
||||||
|
// This structure tracks the current values of push constants as well as dirty bits for push constants
|
||||||
|
// that should be applied before the next draw or dispatch.
|
||||||
|
struct PushConstantTracker {
|
||||||
|
PerStage<std::array<uint32_t, kMaxPushConstants>> values;
|
||||||
|
PerStage<std::bitset<kMaxPushConstants>> dirtyBits;
|
||||||
|
|
||||||
|
void OnBeginPass() {
|
||||||
|
for (auto stage : IterateStages(kAllStages)) {
|
||||||
|
values[stage].fill(0);
|
||||||
|
// No need to set dirty bits are a pipeline will be set before the next operation
|
||||||
|
// using push constants.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnSetPushConstants(nxt::ShaderStageBit stages, uint32_t count,
|
||||||
|
uint32_t offset, const uint32_t* data) {
|
||||||
|
for (auto stage : IterateStages(stages)) {
|
||||||
|
memcpy(&values[stage][offset], data, count * sizeof(uint32_t));
|
||||||
|
|
||||||
|
// Use 64 bit masks and make sure there are no shift UB
|
||||||
|
static_assert(kMaxPushConstants <= 8 * sizeof(unsigned long long) - 1, "");
|
||||||
|
dirtyBits[stage] |= ((1ull << count) - 1ull) << offset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnSetPipeline(PipelineBase* pipeline) {
|
||||||
|
for (auto stage : IterateStages(kAllStages)) {
|
||||||
|
dirtyBits[stage] = pipeline->GetPushConstants(stage).mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Apply(PipelineBase* pipeline, PipelineGL* glPipeline) {
|
||||||
|
for (auto stage : IterateStages(kAllStages)) {
|
||||||
|
const auto& pushConstants = pipeline->GetPushConstants(stage);
|
||||||
|
const auto& glPushConstants = glPipeline->GetGLPushConstants(stage);
|
||||||
|
|
||||||
|
for (uint32_t constant : IterateBitSet(dirtyBits[stage] & pushConstants.mask)) {
|
||||||
|
GLint location = glPushConstants[constant];
|
||||||
|
switch (pushConstants.types[constant]) {
|
||||||
|
case PushConstantType::Int:
|
||||||
|
glUniform1i(location, *reinterpret_cast<GLint*>(&values[stage][constant]));
|
||||||
|
break;
|
||||||
|
case PushConstantType::UInt:
|
||||||
|
glUniform1ui(location, *reinterpret_cast<GLuint*>(&values[stage][constant]));
|
||||||
|
break;
|
||||||
|
case PushConstantType::Float:
|
||||||
|
glUniform1f(location, *reinterpret_cast<GLfloat*>(&values[stage][constant]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
CommandBuffer::CommandBuffer(CommandBufferBuilder* builder)
|
CommandBuffer::CommandBuffer(CommandBufferBuilder* builder)
|
||||||
: CommandBufferBase(builder), commands(builder->AcquireCommands()) {
|
: CommandBufferBase(builder), commands(builder->AcquireCommands()) {
|
||||||
}
|
}
|
||||||
@ -71,6 +134,8 @@ namespace opengl {
|
|||||||
PersistentPipelineState persistentPipelineState;
|
PersistentPipelineState persistentPipelineState;
|
||||||
persistentPipelineState.SetDefaultState();
|
persistentPipelineState.SetDefaultState();
|
||||||
|
|
||||||
|
PushConstantTracker pushConstants;
|
||||||
|
|
||||||
RenderPass* currentRenderPass = nullptr;
|
RenderPass* currentRenderPass = nullptr;
|
||||||
Framebuffer* currentFramebuffer = nullptr;
|
Framebuffer* currentFramebuffer = nullptr;
|
||||||
uint32_t currentSubpass = 0;
|
uint32_t currentSubpass = 0;
|
||||||
@ -81,6 +146,7 @@ namespace opengl {
|
|||||||
case Command::BeginComputePass:
|
case Command::BeginComputePass:
|
||||||
{
|
{
|
||||||
commands.NextCommand<BeginComputePassCmd>();
|
commands.NextCommand<BeginComputePassCmd>();
|
||||||
|
pushConstants.OnBeginPass();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -96,6 +162,7 @@ namespace opengl {
|
|||||||
case Command::BeginRenderSubpass:
|
case Command::BeginRenderSubpass:
|
||||||
{
|
{
|
||||||
commands.NextCommand<BeginRenderSubpassCmd>();
|
commands.NextCommand<BeginRenderSubpassCmd>();
|
||||||
|
pushConstants.OnBeginPass();
|
||||||
|
|
||||||
// TODO(kainino@chromium.org): This is added to possibly
|
// TODO(kainino@chromium.org): This is added to possibly
|
||||||
// work around an issue seen on Windows/Intel. It should
|
// work around an issue seen on Windows/Intel. It should
|
||||||
@ -284,6 +351,7 @@ namespace opengl {
|
|||||||
case Command::Dispatch:
|
case Command::Dispatch:
|
||||||
{
|
{
|
||||||
DispatchCmd* dispatch = commands.NextCommand<DispatchCmd>();
|
DispatchCmd* dispatch = commands.NextCommand<DispatchCmd>();
|
||||||
|
pushConstants.Apply(lastPipeline, lastGLPipeline);
|
||||||
glDispatchCompute(dispatch->x, dispatch->y, dispatch->z);
|
glDispatchCompute(dispatch->x, dispatch->y, dispatch->z);
|
||||||
// TODO(cwallez@chromium.org): add barriers to the API
|
// TODO(cwallez@chromium.org): add barriers to the API
|
||||||
glMemoryBarrier(GL_ALL_BARRIER_BITS);
|
glMemoryBarrier(GL_ALL_BARRIER_BITS);
|
||||||
@ -293,6 +361,8 @@ namespace opengl {
|
|||||||
case Command::DrawArrays:
|
case Command::DrawArrays:
|
||||||
{
|
{
|
||||||
DrawArraysCmd* draw = commands.NextCommand<DrawArraysCmd>();
|
DrawArraysCmd* draw = commands.NextCommand<DrawArraysCmd>();
|
||||||
|
pushConstants.Apply(lastPipeline, lastGLPipeline);
|
||||||
|
|
||||||
if (draw->firstInstance > 0) {
|
if (draw->firstInstance > 0) {
|
||||||
glDrawArraysInstancedBaseInstance(lastRenderPipeline->GetGLPrimitiveTopology(),
|
glDrawArraysInstancedBaseInstance(lastRenderPipeline->GetGLPrimitiveTopology(),
|
||||||
draw->firstVertex, draw->vertexCount, draw->instanceCount, draw->firstInstance);
|
draw->firstVertex, draw->vertexCount, draw->instanceCount, draw->firstInstance);
|
||||||
@ -307,6 +377,8 @@ namespace opengl {
|
|||||||
case Command::DrawElements:
|
case Command::DrawElements:
|
||||||
{
|
{
|
||||||
DrawElementsCmd* draw = commands.NextCommand<DrawElementsCmd>();
|
DrawElementsCmd* draw = commands.NextCommand<DrawElementsCmd>();
|
||||||
|
pushConstants.Apply(lastPipeline, lastGLPipeline);
|
||||||
|
|
||||||
size_t formatSize = IndexFormatSize(indexBufferFormat);
|
size_t formatSize = IndexFormatSize(indexBufferFormat);
|
||||||
GLenum formatType = IndexFormatType(indexBufferFormat);
|
GLenum formatType = IndexFormatType(indexBufferFormat);
|
||||||
|
|
||||||
@ -352,6 +424,7 @@ namespace opengl {
|
|||||||
ToBackend(cmd->pipeline)->ApplyNow();
|
ToBackend(cmd->pipeline)->ApplyNow();
|
||||||
lastGLPipeline = ToBackend(cmd->pipeline).Get();
|
lastGLPipeline = ToBackend(cmd->pipeline).Get();
|
||||||
lastPipeline = ToBackend(cmd->pipeline).Get();
|
lastPipeline = ToBackend(cmd->pipeline).Get();
|
||||||
|
pushConstants.OnSetPipeline(lastPipeline);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -362,35 +435,15 @@ namespace opengl {
|
|||||||
lastRenderPipeline = ToBackend(cmd->pipeline).Get();
|
lastRenderPipeline = ToBackend(cmd->pipeline).Get();
|
||||||
lastGLPipeline = ToBackend(cmd->pipeline).Get();
|
lastGLPipeline = ToBackend(cmd->pipeline).Get();
|
||||||
lastPipeline = ToBackend(cmd->pipeline).Get();
|
lastPipeline = ToBackend(cmd->pipeline).Get();
|
||||||
|
pushConstants.OnSetPipeline(lastPipeline);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Command::SetPushConstants:
|
case Command::SetPushConstants:
|
||||||
{
|
{
|
||||||
SetPushConstantsCmd* cmd = commands.NextCommand<SetPushConstantsCmd>();
|
SetPushConstantsCmd* cmd = commands.NextCommand<SetPushConstantsCmd>();
|
||||||
uint32_t* valuesUInt = commands.NextData<uint32_t>(cmd->count);
|
uint32_t* data = commands.NextData<uint32_t>(cmd->count);
|
||||||
int32_t* valuesInt = reinterpret_cast<int32_t*>(valuesUInt);
|
pushConstants.OnSetPushConstants(cmd->stages, cmd->count, cmd->offset, data);
|
||||||
float* valuesFloat = reinterpret_cast<float*>(valuesUInt);
|
|
||||||
|
|
||||||
for (auto stage : IterateStages(cmd->stages)) {
|
|
||||||
const auto& pushConstants = lastPipeline->GetPushConstants(stage);
|
|
||||||
const auto& glPushConstants = lastGLPipeline->GetGLPushConstants(stage);
|
|
||||||
for (size_t i = 0; i < cmd->count; i++) {
|
|
||||||
GLint location = glPushConstants[cmd->offset + i];
|
|
||||||
|
|
||||||
switch (pushConstants.types[cmd->offset + i]) {
|
|
||||||
case PushConstantType::Int:
|
|
||||||
glUniform1i(location, valuesInt[i]);
|
|
||||||
break;
|
|
||||||
case PushConstantType::UInt:
|
|
||||||
glUniform1ui(location, valuesUInt[i]);
|
|
||||||
break;
|
|
||||||
case PushConstantType::Float:
|
|
||||||
glUniform1f(location, valuesFloat[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -418,11 +471,7 @@ namespace opengl {
|
|||||||
const auto& layout = group->GetLayout()->GetBindingInfo();
|
const auto& layout = group->GetLayout()->GetBindingInfo();
|
||||||
|
|
||||||
// TODO(cwallez@chromium.org): iterate over the layout bitmask instead
|
// TODO(cwallez@chromium.org): iterate over the layout bitmask instead
|
||||||
for (size_t binding = 0; binding < kMaxBindingsPerGroup; ++binding) {
|
for (uint32_t binding : IterateBitSet(layout.mask)) {
|
||||||
if (!layout.mask[binding]) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (layout.types[binding]) {
|
switch (layout.types[binding]) {
|
||||||
case nxt::BindingType::UniformBuffer:
|
case nxt::BindingType::UniformBuffer:
|
||||||
{
|
{
|
||||||
|
@ -59,7 +59,6 @@ namespace opengl {
|
|||||||
auto depthStencilState = ToBackend(GetDepthStencilState());
|
auto depthStencilState = ToBackend(GetDepthStencilState());
|
||||||
depthStencilState->ApplyNow(persistentPipelineState);
|
depthStencilState->ApplyNow(persistentPipelineState);
|
||||||
|
|
||||||
|
|
||||||
RenderPass* renderPass = ToBackend(GetRenderPass());
|
RenderPass* renderPass = ToBackend(GetRenderPass());
|
||||||
auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
|
auto& subpassInfo = renderPass->GetSubpassInfo(GetSubPass());
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user