diff --git a/src/modules/graphics/metal/Graphics.h b/src/modules/graphics/metal/Graphics.h index c57684b6c..c7331ba37 100644 --- a/src/modules/graphics/metal/Graphics.h +++ b/src/modules/graphics/metal/Graphics.h @@ -210,7 +210,7 @@ private: id getCachedDepthStencilState(const DepthState &depth, const StencilState &stencil); void applyRenderState(id renderEncoder, VertexAttributesID attributesID); bool applyShaderUniforms(id encoder, love::graphics::Shader *shader); - void applyShaderUniforms(id renderEncoder, love::graphics::Shader *shader, Texture *maintex); + bool applyShaderUniforms(id renderEncoder, love::graphics::Shader *shader, Texture *maintex); id commandQueue; diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index fdbeefbe3..23dde4676 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -1105,7 +1105,7 @@ bool Graphics::applyShaderUniforms(id encoder, love::g return allWritableVariablesSet; } -void Graphics::applyShaderUniforms(id renderEncoder, love::graphics::Shader *shader, love::graphics::Texture *maintex) +bool Graphics::applyShaderUniforms(id renderEncoder, love::graphics::Shader *shader, love::graphics::Texture *maintex) { Shader *s = (Shader *)shader; @@ -1168,6 +1168,8 @@ void Graphics::applyShaderUniforms(id renderEncoder, lo uniformBufferOffset += alignUp(size, alignment); + bool allWritableVariablesSet = true; + for (const Shader::TextureBinding &b : s->getTextureBindings()) { id texture = b.texture; @@ -1183,7 +1185,13 @@ void Graphics::applyShaderUniforms(id renderEncoder, lo uint8 sampindex = b.samplerStages[SHADERSTAGE_VERTEX]; if (texindex != LOVE_UINT8_MAX) + { setTexture(renderEncoder, bindings, SHADERSTAGE_VERTEX, texindex, texture); + + if ((b.access & Shader::ACCESS_WRITE) != 0 && texture == nil) + allWritableVariablesSet = false; + } + if (sampindex != LOVE_UINT8_MAX) setSampler(renderEncoder, bindings, SHADERSTAGE_VERTEX, sampindex, samplertex); @@ -1191,7 +1199,13 @@ void Graphics::applyShaderUniforms(id renderEncoder, lo sampindex = b.samplerStages[SHADERSTAGE_PIXEL]; if (texindex != LOVE_UINT8_MAX) + { setTexture(renderEncoder, bindings, SHADERSTAGE_PIXEL, texindex, texture); + + if ((b.access & Shader::ACCESS_WRITE) != 0 && texture == nil) + allWritableVariablesSet = false; + } + if (sampindex != LOVE_UINT8_MAX) setSampler(renderEncoder, bindings, SHADERSTAGE_PIXEL, sampindex, samplertex); } @@ -1200,11 +1214,24 @@ void Graphics::applyShaderUniforms(id renderEncoder, lo { uint8 index = b.stages[SHADERSTAGE_VERTEX]; if (index != LOVE_UINT8_MAX) + { setBuffer(renderEncoder, bindings, SHADERSTAGE_VERTEX, index, b.buffer, 0); + + if ((b.access & Shader::ACCESS_WRITE) != 0 && b.buffer == nil) + allWritableVariablesSet = false; + } + index = b.stages[SHADERSTAGE_PIXEL]; if (index != LOVE_UINT8_MAX) + { setBuffer(renderEncoder, bindings, SHADERSTAGE_PIXEL, index, b.buffer, 0); + + if ((b.access & Shader::ACCESS_WRITE) != 0 && b.buffer == nil) + allWritableVariablesSet = false; + } } + + return allWritableVariablesSet; } static void setVertexBuffers(id encoder, love::graphics::Shader *shader, const BufferBindings *buffers, Graphics::RenderEncoderBindings &bindings) @@ -1240,7 +1267,8 @@ void Graphics::draw(const DrawCommand &cmd) } applyRenderState(encoder, cmd.attributesID); - applyShaderUniforms(encoder, Shader::current, cmd.texture); + if (!applyShaderUniforms(encoder, Shader::current, cmd.texture)) + return; setVertexBuffers(encoder, Shader::current, cmd.buffers, renderBindings); @@ -1272,7 +1300,8 @@ void Graphics::draw(const DrawIndexedCommand &cmd) } applyRenderState(encoder, cmd.attributesID); - applyShaderUniforms(encoder, Shader::current, cmd.texture); + if (!applyShaderUniforms(encoder, Shader::current, cmd.texture)) + return; setVertexBuffers(encoder, Shader::current, cmd.buffers, renderBindings); @@ -1337,7 +1366,8 @@ void Graphics::drawQuads(int start, int count, VertexAttributesID attributesID, } applyRenderState(encoder, attributesID); - applyShaderUniforms(encoder, Shader::current, texture); + if (!applyShaderUniforms(encoder, Shader::current, texture)) + return; id ib = getMTLBuffer(quadIndexBuffer); diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 4baa7b9e3..6e8f2ba31 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -562,7 +562,9 @@ void Graphics::draw(const DrawCommand &cmd) GLbitfield preDrawBarriers = 0; GLbitfield postDrawBarriers = 0; - shaderBarriers((Shader *)Shader::current, preDrawBarriers, postDrawBarriers); + if (!shaderBarriers((Shader *)Shader::current, preDrawBarriers, postDrawBarriers)) + return; + if (preDrawBarriers != 0) glMemoryBarrier(preDrawBarriers); @@ -597,7 +599,9 @@ void Graphics::draw(const DrawIndexedCommand &cmd) GLbitfield preDrawBarriers = 0; GLbitfield postDrawBarriers = 0; - shaderBarriers((Shader *)Shader::current, preDrawBarriers, postDrawBarriers); + if (!shaderBarriers((Shader *)Shader::current, preDrawBarriers, postDrawBarriers)) + return; + if (preDrawBarriers != 0) glMemoryBarrier(preDrawBarriers); @@ -661,7 +665,8 @@ void Graphics::drawQuads(int start, int count, VertexAttributesID attributesID, GLbitfield preDrawBarriers = 0; GLbitfield postDrawBarriers = 0; - shaderBarriers((Shader *)Shader::current, preDrawBarriers, postDrawBarriers); + if (!shaderBarriers((Shader *)Shader::current, preDrawBarriers, postDrawBarriers)) + return; VertexAttributes attributes; findVertexAttributes(attributesID, attributes); diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 854832de0..f2673fa6a 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -957,6 +957,11 @@ void Graphics::draw(const DrawCommand &cmd) { prepareDraw(cmd.attributesID, *cmd.buffers, cmd.texture, cmd.primitiveType, cmd.cullMode); + VkAccessFlags dstAccessMask; + VkPipelineStageFlags dstStageMask; + if (!prepareBarrier(dstAccessMask, dstStageMask)) + return; + if (cmd.indirectBuffer != nullptr) { vkCmdDrawIndirect( @@ -976,7 +981,7 @@ void Graphics::draw(const DrawCommand &cmd) 0); } - endDraw(); + tryBarrier(dstAccessMask, dstStageMask); drawCalls++; } @@ -984,6 +989,11 @@ void Graphics::draw(const DrawIndexedCommand &cmd) { prepareDraw(cmd.attributesID, *cmd.buffers, cmd.texture, cmd.primitiveType, cmd.cullMode); + VkAccessFlags dstAccessMask; + VkPipelineStageFlags dstStageMask; + if (!prepareBarrier(dstAccessMask, dstStageMask)) + return; + vkCmdBindIndexBuffer( commandBuffers.at(currentFrame), (VkBuffer) cmd.indexBuffer->getHandle(), @@ -1010,7 +1020,7 @@ void Graphics::draw(const DrawIndexedCommand &cmd) 0); } - endDraw(); + tryBarrier(dstAccessMask, dstStageMask); drawCalls++; } @@ -1021,6 +1031,12 @@ void Graphics::drawQuads(int start, int count, VertexAttributesID attributesID, prepareDraw(attributesID, buffers, texture, PRIMITIVE_TRIANGLES, CULL_NONE); + VkAccessFlags dstAccessMask; + VkPipelineStageFlags dstStageMask; + if (!prepareBarrier(dstAccessMask, dstStageMask)) + return; + + vkCmdBindIndexBuffer( commandBuffers.at(currentFrame), (VkBuffer)quadIndexBuffer->getHandle(), @@ -1042,7 +1058,7 @@ void Graphics::drawQuads(int start, int count, VertexAttributesID attributesID, 0); baseVertex += quadcount * 4; - endDraw(); + tryBarrier(dstAccessMask, dstStageMask); drawCalls++; } } @@ -2785,18 +2801,27 @@ void Graphics::prepareDraw(VertexAttributesID attributesID, const BufferBindings vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), VERTEX_BUFFER_BINDING_START, buffercount, vkbuffers, vkoffsets); } -void Graphics::endDraw() +bool Graphics::prepareBarrier(VkAccessFlags &dstAccessMask, VkPipelineStageFlags &dstStageMask) { auto shader = dynamic_cast(Shader::current); if (!shader) + return false; + + if (!shaderBarrierFlags(shader, dstAccessMask, dstStageMask)) + return false; + + return true; +} + +void Graphics::tryBarrier(VkAccessFlags dstAccessMask, VkPipelineStageFlags dstStageMask) +{ + if (dstAccessMask == 0 && dstStageMask == 0) return; VkMemoryBarrier barrier{}; barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER; barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - VkPipelineStageFlags dstStageMask = 0; - if (!shaderBarrierFlags(shader, barrier.dstAccessMask, dstStageMask)) - return; + barrier.dstAccessMask = dstAccessMask; if (barrier.dstAccessMask != 0 || dstStageMask != 0) vkCmdPipelineBarrier(commandBuffers.at(currentFrame), VK_PIPELINE_STAGE_VERTEX_SHADER_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, dstStageMask, 0, 1, &barrier, 0, nullptr, 0, nullptr); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 6016c230c..fc7f60133 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -372,6 +372,8 @@ private: VertexAttributesID attributesID, const BufferBindings &buffers, graphics::Texture *texture, PrimitiveType, CullMode); + bool prepareBarrier(VkAccessFlags &dstAccessMask, VkPipelineStageFlags &dstStageMask); + void tryBarrier(VkAccessFlags dstAccessMask, VkPipelineStageFlags dstStageMask); void setRenderPass(const RenderTargets &rts, int pixelw, int pixelh); void setDefaultRenderPass(); void startRenderPass(); @@ -379,7 +381,6 @@ private: void applyScissor(); VkSampler createSampler(const SamplerState &sampler); void requestSwapchainRecreation(); - void endDraw(); VkInstance instance = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;