mirror of
https://github.com/love2d/love.git
synced 2026-08-12 00:20:52 +02:00
Relax storage restrictions on vertex/pixel shaders.
This commit is contained in:
@@ -566,7 +566,7 @@ bool Graphics::validateShader(bool gles, const std::vector<std::string> &stagess
|
||||
}
|
||||
}
|
||||
|
||||
return Shader::validate(stages, err);
|
||||
return Shader::validate(stages, err, options);
|
||||
}
|
||||
|
||||
Texture *Graphics::getDefaultTexture(TextureType type, DataBaseType dataType, bool depthSample)
|
||||
|
||||
@@ -650,7 +650,7 @@ Shader::Shader(StrongRef<ShaderStage> _stages[], const CompileOptions &options)
|
||||
, debugName(options.debugName)
|
||||
{
|
||||
std::string err;
|
||||
if (!validateInternal(_stages, err, reflection))
|
||||
if (!validateInternal(_stages, err, reflection, options))
|
||||
throw love::Exception("%s", err.c_str());
|
||||
|
||||
std::vector<std::string> unsetVertexInputLocations;
|
||||
@@ -1029,10 +1029,10 @@ bool Shader::isUsingDeprecatedTextureUniform() const
|
||||
return it != reflection.allUniforms.end() && it->second->stageMask != 0;
|
||||
}
|
||||
|
||||
bool Shader::validate(StrongRef<ShaderStage> stages[], std::string& err)
|
||||
bool Shader::validate(StrongRef<ShaderStage> stages[], std::string& err, const CompileOptions &options)
|
||||
{
|
||||
Reflection reflection;
|
||||
return validateInternal(stages, err, reflection);
|
||||
return validateInternal(stages, err, reflection, options);
|
||||
}
|
||||
|
||||
static DataBaseType getBaseType(glslang::TBasicType basictype)
|
||||
@@ -1246,7 +1246,7 @@ static bool AddFieldsToFormat(std::vector<Buffer::DataDeclaration> &format, int
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err, Reflection &reflection)
|
||||
bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err, Reflection &reflection, const CompileOptions &options)
|
||||
{
|
||||
glslang::TProgram program;
|
||||
|
||||
@@ -1349,9 +1349,9 @@ bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err,
|
||||
}
|
||||
else if (type->isImage())
|
||||
{
|
||||
if ((info.stages & (~EShLangComputeMask)) != 0)
|
||||
if ((info.stages & (~EShLangComputeMask)) != 0 && !options.features[FEATURE_STORAGE_TEXTURES])
|
||||
{
|
||||
err = "Shader validation error:\nStorage Texture uniform variables (image2D, etc) are only allowed in compute shaders.";
|
||||
err = "Shader validation error:\nStorage Texture uniform variables (image2D, etc) are only allowed in compute shaders unless explicitly enabled.";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1467,9 +1467,9 @@ bool Shader::validateInternal(StrongRef<ShaderStage> stages[], std::string &err,
|
||||
{
|
||||
const glslang::TQualifier &qualifiers = type->getQualifier();
|
||||
|
||||
if ((!qualifiers.isReadOnly() || qualifiers.isWriteOnly()) && ((info.stages & (~EShLangComputeMask)) != 0))
|
||||
if ((!qualifiers.isReadOnly() || qualifiers.isWriteOnly()) && ((info.stages & (~EShLangComputeMask)) != 0) && !options.features[FEATURE_WRITABLE_BUFFERS])
|
||||
{
|
||||
err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must be marked as readonly in vertex and pixel shaders.";
|
||||
err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must be marked as readonly in vertex and pixel shaders unless explicitly enabled.";
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1872,5 +1872,11 @@ bool Shader::getConstant(BuiltinUniform in, const char *&out)
|
||||
return builtinNames.find(in, out);
|
||||
}
|
||||
|
||||
STRINGMAP_CLASS_BEGIN(Shader, Shader::Feature, Shader::FEATURE_MAX_ENUM, feature)
|
||||
{
|
||||
{ "write", Shader::FEATURE_WRITE },
|
||||
}
|
||||
STRINGMAP_CLASS_END(Shader, Shader::Feature, Shader::FEATURE_MAX_ENUM, feature)
|
||||
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -56,6 +56,12 @@ public:
|
||||
LANGUAGE_MAX_ENUM
|
||||
};
|
||||
|
||||
enum Feature
|
||||
{
|
||||
FEATURE_WRITE,
|
||||
FEATURE_MAX_ENUM
|
||||
};
|
||||
|
||||
// Built-in uniform variables.
|
||||
enum BuiltinUniform
|
||||
{
|
||||
@@ -119,6 +125,7 @@ public:
|
||||
{
|
||||
std::map<std::string, std::string> defines;
|
||||
std::string debugName;
|
||||
bool features[FEATURE_MAX_ENUM] = {};
|
||||
};
|
||||
|
||||
struct SourceInfo
|
||||
@@ -275,7 +282,7 @@ public:
|
||||
static SourceInfo getSourceInfo(const std::string &src);
|
||||
static std::string createShaderStageCode(Graphics *gfx, ShaderStageType stage, const std::string &code, const CompileOptions &options, const SourceInfo &info, bool gles, bool checksystemfeatures);
|
||||
|
||||
static bool validate(StrongRef<ShaderStage> stages[], std::string &err);
|
||||
static bool validate(StrongRef<ShaderStage> stages[], std::string &err, const CompileOptions &options);
|
||||
|
||||
static bool initialize();
|
||||
static void deinitialize();
|
||||
@@ -288,6 +295,8 @@ public:
|
||||
static bool getConstant(const char *in, BuiltinUniform &out);
|
||||
static bool getConstant(BuiltinUniform in, const char *&out);
|
||||
|
||||
STRINGMAP_CLASS_DECLARE(Feature);
|
||||
|
||||
protected:
|
||||
|
||||
struct Reflection
|
||||
@@ -330,7 +339,7 @@ protected:
|
||||
|
||||
static std::string canonicaliizeUniformName(const std::string &name);
|
||||
static size_t getUniformDataSizePacked(const UniformInfo &u);
|
||||
static bool validateInternal(StrongRef<ShaderStage> stages[], std::string& err, Reflection &reflection);
|
||||
static bool validateInternal(StrongRef<ShaderStage> stages[], std::string& err, Reflection &reflection, const CompileOptions &options);
|
||||
static DataBaseType getDataBaseType(PixelFormat format);
|
||||
static bool isResourceBaseTypeCompatible(DataBaseType a, DataBaseType b);
|
||||
|
||||
|
||||
@@ -444,7 +444,7 @@ void Graphics::setActive(bool enable)
|
||||
active = enable;
|
||||
}
|
||||
|
||||
static bool computeDispatchBarriers(Shader *shader, GLbitfield &preDispatchBarriers, GLbitfield &postDispatchBarriers)
|
||||
static bool shaderBarriers(Shader *shader, GLbitfield &preDispatchBarriers, GLbitfield &postDispatchBarriers)
|
||||
{
|
||||
for (auto buffer : shader->getActiveWritableStorageBuffers())
|
||||
{
|
||||
@@ -505,7 +505,7 @@ bool Graphics::dispatch(love::graphics::Shader *s, int x, int y, int z)
|
||||
GLbitfield preDispatchBarriers = 0;
|
||||
GLbitfield postDispatchBarriers = 0;
|
||||
|
||||
if (!computeDispatchBarriers(shader, preDispatchBarriers, postDispatchBarriers))
|
||||
if (!shaderBarriers(shader, preDispatchBarriers, postDispatchBarriers))
|
||||
return false;
|
||||
|
||||
// glMemoryBarrier before dispatch to make sure non-compute-read ->
|
||||
@@ -534,7 +534,7 @@ bool Graphics::dispatch(love::graphics::Shader *s, love::graphics::Buffer *indir
|
||||
GLbitfield preDispatchBarriers = 0;
|
||||
GLbitfield postDispatchBarriers = 0;
|
||||
|
||||
if (!computeDispatchBarriers(shader, preDispatchBarriers, postDispatchBarriers))
|
||||
if (!shaderBarriers(shader, preDispatchBarriers, postDispatchBarriers))
|
||||
return false;
|
||||
|
||||
if (preDispatchBarriers != 0)
|
||||
@@ -559,6 +559,13 @@ void Graphics::draw(const DrawCommand &cmd)
|
||||
VertexAttributes attributes;
|
||||
findVertexAttributes(cmd.attributesID, attributes);
|
||||
|
||||
GLbitfield preDrawBarriers = 0;
|
||||
GLbitfield postDrawBarriers = 0;
|
||||
|
||||
shaderBarriers((Shader *)Shader::current, preDrawBarriers, postDrawBarriers);
|
||||
if (preDrawBarriers != 0)
|
||||
glMemoryBarrier(preDrawBarriers);
|
||||
|
||||
gl.prepareDraw(this);
|
||||
gl.setVertexAttributes(attributes, *cmd.buffers);
|
||||
gl.bindTextureToUnit(cmd.texture, 0, false);
|
||||
@@ -576,6 +583,9 @@ void Graphics::draw(const DrawCommand &cmd)
|
||||
else
|
||||
glDrawArrays(glprimitivetype, cmd.vertexStart, cmd.vertexCount);
|
||||
|
||||
if (postDrawBarriers != 0)
|
||||
glMemoryBarrier(postDrawBarriers);
|
||||
|
||||
++drawCalls;
|
||||
}
|
||||
|
||||
@@ -584,6 +594,13 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
|
||||
VertexAttributes attributes;
|
||||
findVertexAttributes(cmd.attributesID, attributes);
|
||||
|
||||
GLbitfield preDrawBarriers = 0;
|
||||
GLbitfield postDrawBarriers = 0;
|
||||
|
||||
shaderBarriers((Shader *)Shader::current, preDrawBarriers, postDrawBarriers);
|
||||
if (preDrawBarriers != 0)
|
||||
glMemoryBarrier(preDrawBarriers);
|
||||
|
||||
gl.prepareDraw(this);
|
||||
gl.setVertexAttributes(attributes, *cmd.buffers);
|
||||
gl.bindTextureToUnit(cmd.texture, 0, false);
|
||||
@@ -607,6 +624,9 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
|
||||
else
|
||||
glDrawElements(glprimitivetype, cmd.indexCount, gldatatype, gloffset);
|
||||
|
||||
if (postDrawBarriers != 0)
|
||||
glMemoryBarrier(postDrawBarriers);
|
||||
|
||||
++drawCalls;
|
||||
}
|
||||
|
||||
@@ -638,6 +658,11 @@ void Graphics::drawQuads(int start, int count, VertexAttributesID attributesID,
|
||||
const int MAX_VERTICES_PER_DRAW = LOVE_UINT16_MAX;
|
||||
const int MAX_QUADS_PER_DRAW = MAX_VERTICES_PER_DRAW / 4;
|
||||
|
||||
GLbitfield preDrawBarriers = 0;
|
||||
GLbitfield postDrawBarriers = 0;
|
||||
|
||||
shaderBarriers((Shader *)Shader::current, preDrawBarriers, postDrawBarriers);
|
||||
|
||||
VertexAttributes attributes;
|
||||
findVertexAttributes(attributesID, attributes);
|
||||
|
||||
@@ -655,9 +680,16 @@ void Graphics::drawQuads(int start, int count, VertexAttributesID attributesID,
|
||||
|
||||
for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW)
|
||||
{
|
||||
if (preDrawBarriers != 0)
|
||||
glMemoryBarrier(preDrawBarriers);
|
||||
|
||||
int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex);
|
||||
|
||||
glDrawElementsBaseVertex(GL_TRIANGLES, quadcount * 6, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0), basevertex);
|
||||
|
||||
if (postDrawBarriers != 0)
|
||||
glMemoryBarrier(postDrawBarriers);
|
||||
|
||||
++drawCalls;
|
||||
|
||||
basevertex += quadcount * 4;
|
||||
@@ -671,11 +703,18 @@ void Graphics::drawQuads(int start, int count, VertexAttributesID attributesID,
|
||||
|
||||
for (int quadindex = 0; quadindex < count; quadindex += MAX_QUADS_PER_DRAW)
|
||||
{
|
||||
if (preDrawBarriers != 0)
|
||||
glMemoryBarrier(preDrawBarriers);
|
||||
|
||||
gl.setVertexAttributes(attributes, bufferscopy);
|
||||
|
||||
int quadcount = std::min(MAX_QUADS_PER_DRAW, count - quadindex);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, quadcount * 6, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
|
||||
|
||||
if (postDrawBarriers != 0)
|
||||
glMemoryBarrier(postDrawBarriers);
|
||||
|
||||
++drawCalls;
|
||||
|
||||
if (count > MAX_QUADS_PER_DRAW)
|
||||
|
||||
@@ -972,6 +972,7 @@ void Graphics::draw(const DrawCommand &cmd)
|
||||
0);
|
||||
}
|
||||
|
||||
endDraw();
|
||||
drawCalls++;
|
||||
}
|
||||
|
||||
@@ -1005,6 +1006,7 @@ void Graphics::draw(const DrawIndexedCommand &cmd)
|
||||
0);
|
||||
}
|
||||
|
||||
endDraw();
|
||||
drawCalls++;
|
||||
}
|
||||
|
||||
@@ -1036,6 +1038,7 @@ void Graphics::drawQuads(int start, int count, VertexAttributesID attributesID,
|
||||
0);
|
||||
baseVertex += quadcount * 4;
|
||||
|
||||
endDraw();
|
||||
drawCalls++;
|
||||
}
|
||||
}
|
||||
@@ -1281,7 +1284,7 @@ graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size)
|
||||
return new StreamBuffer(this, type, size);
|
||||
}
|
||||
|
||||
static bool computeDispatchBarrierFlags(Shader *shader, VkAccessFlags &dstAccessFlags, VkPipelineStageFlags &dstStageFlags)
|
||||
static bool shaderBarrierFlags(Shader *shader, VkAccessFlags &dstAccessFlags, VkPipelineStageFlags &dstStageFlags)
|
||||
{
|
||||
for (const auto &info : shader->getActiveTextureInfo())
|
||||
{
|
||||
@@ -1323,7 +1326,7 @@ bool Graphics::dispatch(love::graphics::Shader *shader, int x, int y, int z)
|
||||
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
VkPipelineStageFlags dstStageMask = 0;
|
||||
if (!computeDispatchBarrierFlags(computeShader, barrier.dstAccessMask, dstStageMask))
|
||||
if (!shaderBarrierFlags(computeShader, barrier.dstAccessMask, dstStageMask))
|
||||
return false;
|
||||
|
||||
usedShadersInFrame.insert(computeShader);
|
||||
@@ -1352,7 +1355,7 @@ bool Graphics::dispatch(love::graphics::Shader *shader, love::graphics::Buffer *
|
||||
barrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
|
||||
barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT;
|
||||
VkPipelineStageFlags dstStageMask = 0;
|
||||
if (!computeDispatchBarrierFlags(computeShader, barrier.dstAccessMask, dstStageMask))
|
||||
if (!shaderBarrierFlags(computeShader, barrier.dstAccessMask, dstStageMask))
|
||||
return false;
|
||||
|
||||
usedShadersInFrame.insert(computeShader);
|
||||
@@ -2778,6 +2781,23 @@ void Graphics::prepareDraw(VertexAttributesID attributesID, const BufferBindings
|
||||
vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), VERTEX_BUFFER_BINDING_START, buffercount, vkbuffers, vkoffsets);
|
||||
}
|
||||
|
||||
void Graphics::endDraw()
|
||||
{
|
||||
auto shader = dynamic_cast<Shader *>(Shader::current);
|
||||
if (!shader)
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void Graphics::setDefaultRenderPass()
|
||||
{
|
||||
uint32_t numClearValues = 2;
|
||||
|
||||
@@ -379,6 +379,7 @@ private:
|
||||
void applyScissor();
|
||||
VkSampler createSampler(const SamplerState &sampler);
|
||||
void requestSwapchainRecreation();
|
||||
void endDraw();
|
||||
|
||||
VkInstance instance = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
|
||||
|
||||
@@ -1586,6 +1586,20 @@ static int w_getShaderSource(lua_State *L, int startidx, std::vector<std::string
|
||||
if (!lua_isnoneornil(L, -1))
|
||||
options.debugName = luax_checkstring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
for (int feature = 0; feature < Shader::FEATURE_MAX_ENUM; ++feature)
|
||||
{
|
||||
const char *featureKey;
|
||||
if (Shader::getConstant((Shader::Feature)feature, featureKey))
|
||||
{
|
||||
lua_getfield(L, optionsidx, featureKey);
|
||||
if (!lua_isnoneornil(L, -1))
|
||||
{
|
||||
options.features[feature] = lua_toboolean(L, -1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user