mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
move common shader:send texture/buffer code to platform-agnostic layer.
Fixes issues in the Metal backend when a shader using a readonly buffer is created.
This commit is contained in:
@@ -797,6 +797,125 @@ bool Shader::hasUniform(const std::string &name) const
|
||||
return it != reflection.allUniforms.end() && it->second->active;
|
||||
}
|
||||
|
||||
void Shader::setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture)
|
||||
{
|
||||
const BuiltinUniform builtins[3] = {
|
||||
BUILTIN_TEXTURE_VIDEO_Y,
|
||||
BUILTIN_TEXTURE_VIDEO_CB,
|
||||
BUILTIN_TEXTURE_VIDEO_CR,
|
||||
};
|
||||
|
||||
love::graphics::Texture *textures[3] = {ytexture, cbtexture, crtexture};
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
const UniformInfo *info = getUniformInfo(builtins[i]);
|
||||
if (info != nullptr)
|
||||
sendTextures(info, &textures[i], 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count)
|
||||
{
|
||||
Shader::sendTextures(info, textures, count, false);
|
||||
}
|
||||
|
||||
void Shader::sendBuffers(const UniformInfo *info, Buffer **buffers, int count)
|
||||
{
|
||||
Shader::sendBuffers(info, buffers, count, false);
|
||||
}
|
||||
|
||||
void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalUpdate)
|
||||
{
|
||||
UniformType basetype = info->baseType;
|
||||
|
||||
if (basetype != UNIFORM_SAMPLER && basetype != UNIFORM_STORAGETEXTURE)
|
||||
return;
|
||||
|
||||
if (!internalUpdate && current == this)
|
||||
flushBatchedDraws();
|
||||
|
||||
count = std::min(count, info->count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
love::graphics::Texture *tex = textures[i];
|
||||
bool isdefault = tex == nullptr;
|
||||
|
||||
if (tex != nullptr)
|
||||
{
|
||||
if (!validateTexture(info, tex, internalUpdate))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto gfx = Module::getInstance<love::graphics::Graphics>(Module::M_GRAPHICS);
|
||||
tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType, info->isDepthSampler);
|
||||
}
|
||||
|
||||
tex->retain();
|
||||
|
||||
int resourceindex = info->resourceIndex + i;
|
||||
|
||||
if (activeTextures[resourceindex] != nullptr)
|
||||
activeTextures[resourceindex]->release();
|
||||
|
||||
activeTextures[resourceindex] = tex;
|
||||
|
||||
applyTexture(info, i, tex, basetype, isdefault);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::sendBuffers(const UniformInfo *info, Buffer **buffers, int count, bool internalUpdate)
|
||||
{
|
||||
UniformType basetype = info->baseType;
|
||||
|
||||
if (basetype != UNIFORM_TEXELBUFFER && basetype != UNIFORM_STORAGEBUFFER)
|
||||
return;
|
||||
|
||||
if (!internalUpdate && current == this)
|
||||
flushBatchedDraws();
|
||||
|
||||
count = std::min(count, info->count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
love::graphics::Buffer *buffer = buffers[i];
|
||||
bool isdefault = buffer == nullptr;
|
||||
|
||||
if (buffer != nullptr)
|
||||
{
|
||||
if (!validateBuffer(info, buffer, internalUpdate))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto gfx = Module::getInstance<love::graphics::Graphics>(Module::M_GRAPHICS);
|
||||
if (basetype == UNIFORM_TEXELBUFFER)
|
||||
buffer = gfx->getDefaultTexelBuffer(info->dataBaseType);
|
||||
else
|
||||
buffer = gfx->getDefaultStorageBuffer();
|
||||
}
|
||||
|
||||
buffer->retain();
|
||||
|
||||
int resourceindex = info->resourceIndex + i;
|
||||
|
||||
if (activeBuffers[resourceindex] != nullptr)
|
||||
activeBuffers[resourceindex]->release();
|
||||
|
||||
activeBuffers[resourceindex] = buffer;
|
||||
|
||||
applyBuffer(info, i, buffer, basetype, isdefault);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::flushBatchedDraws() const
|
||||
{
|
||||
if (current == this)
|
||||
Graphics::flushBatchedDrawsGlobal();
|
||||
}
|
||||
|
||||
const Shader::UniformInfo *Shader::getMainTextureInfo() const
|
||||
{
|
||||
return getUniformInfo(BUILTIN_TEXTURE_MAIN);
|
||||
@@ -1532,17 +1651,15 @@ bool Shader::validateBuffer(const UniformInfo *info, Buffer *buffer, bool intern
|
||||
{
|
||||
if (info->bufferStride != buffer->getArrayStride())
|
||||
{
|
||||
if (internalUpdate)
|
||||
return false;
|
||||
else
|
||||
// Don't prevent this from working for internally bound default resources.
|
||||
if (!internalUpdate)
|
||||
throw love::Exception("Shader storage block '%s' has an array stride of %d bytes, but the given Buffer has an array stride of %d bytes.",
|
||||
info->name.c_str(), info->bufferStride, buffer->getArrayStride());
|
||||
}
|
||||
else if (info->bufferMemberCount != buffer->getDataMembers().size())
|
||||
{
|
||||
if (internalUpdate)
|
||||
return false;
|
||||
else
|
||||
// Don't prevent this from working for internally bound default resources.
|
||||
if (!internalUpdate)
|
||||
throw love::Exception("Shader storage block '%s' has a struct with %d fields, but the given Buffer has a format with %d members.",
|
||||
info->name.c_str(), info->bufferMemberCount, buffer->getDataMembers().size());
|
||||
}
|
||||
|
||||
@@ -245,8 +245,8 @@ public:
|
||||
|
||||
virtual void updateUniform(const UniformInfo *info, int count) = 0;
|
||||
|
||||
virtual void sendTextures(const UniformInfo *info, Texture **textures, int count) = 0;
|
||||
virtual void sendBuffers(const UniformInfo *info, Buffer **buffers, int count) = 0;
|
||||
void sendTextures(const UniformInfo *info, Texture **textures, int count);
|
||||
void sendBuffers(const UniformInfo *info, Buffer **buffers, int count);
|
||||
|
||||
/**
|
||||
* Gets whether a uniform with the specified name exists and is actively
|
||||
@@ -257,7 +257,7 @@ public:
|
||||
/**
|
||||
* Sets the textures used when rendering a video. For internal use only.
|
||||
**/
|
||||
virtual void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture) = 0;
|
||||
void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture);
|
||||
|
||||
const UniformInfo *getMainTextureInfo() const;
|
||||
void validateDrawState(PrimitiveType primtype, Texture *maintexture) const;
|
||||
@@ -319,6 +319,14 @@ protected:
|
||||
// std140 uniform buffer alignment-aware copy.
|
||||
void copyToUniformBuffer(const UniformInfo *info, const void *src, void *dst, int count) const;
|
||||
|
||||
void sendTextures(const UniformInfo *info, Texture **textures, int count, bool internalupdate);
|
||||
void sendBuffers(const UniformInfo *info, Buffer **buffers, int count, bool internalupdate);
|
||||
|
||||
virtual void applyTexture(const UniformInfo *info, int i, Texture *texture, UniformType basetype, bool isdefault) = 0;
|
||||
virtual void applyBuffer(const UniformInfo *info, int i, Buffer *buffer, UniformType basetype, bool isdefault) = 0;
|
||||
|
||||
void flushBatchedDraws() const;
|
||||
|
||||
static std::string canonicaliizeUniformName(const std::string &name);
|
||||
static bool validateInternal(StrongRef<ShaderStage> stages[], std::string& err, Reflection &reflection);
|
||||
static DataBaseType getDataBaseType(PixelFormat format);
|
||||
|
||||
@@ -109,10 +109,7 @@ public:
|
||||
int getVertexAttributeIndex(const std::string &name) override;
|
||||
const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override;
|
||||
void updateUniform(const UniformInfo *info, int count) override;
|
||||
void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override;
|
||||
void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override;
|
||||
ptrdiff_t getHandle() const override { return 0; }
|
||||
void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override;
|
||||
|
||||
id<MTLRenderPipelineState> getCachedRenderPipeline(Graphics *gfx, const RenderPipelineKey &key);
|
||||
id<MTLComputePipelineState> getComputePipeline() const { return computePipeline; }
|
||||
@@ -140,6 +137,9 @@ private:
|
||||
void buildLocalUniforms(const spirv_cross::CompilerMSL &msl, const spirv_cross::SPIRType &type, size_t baseoffset, const std::string &basename);
|
||||
void compileFromGLSLang(id<MTLDevice> device, const glslang::TProgram &program);
|
||||
|
||||
void applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType basetype, bool isdefault) override;
|
||||
void applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType basetype, bool isdefault) override;
|
||||
|
||||
id<MTLFunction> functions[SHADERSTAGE_MAX_ENUM];
|
||||
|
||||
UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM];
|
||||
|
||||
@@ -675,11 +675,11 @@ void Shader::compileFromGLSLang(id<MTLDevice> device, const glslang::TProgram &p
|
||||
{
|
||||
case UNIFORM_SAMPLER:
|
||||
case UNIFORM_STORAGETEXTURE:
|
||||
sendTextures(info, &activeTextures[info->resourceIndex], info->count);
|
||||
sendTextures(info, &activeTextures[info->resourceIndex], info->count, true);
|
||||
break;
|
||||
case UNIFORM_TEXELBUFFER:
|
||||
case UNIFORM_STORAGEBUFFER:
|
||||
sendBuffers(info, &activeBuffers[info->resourceIndex], info->count);
|
||||
sendBuffers(info, &activeBuffers[info->resourceIndex], info->count, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -741,139 +741,47 @@ void Shader::updateUniform(const UniformInfo *info, int count)
|
||||
copyToUniformBuffer(info, info->data, dst, count);
|
||||
}
|
||||
|
||||
void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count)
|
||||
void Shader::applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType /*basetype*/, bool isdefault)
|
||||
{ @autoreleasepool {
|
||||
if (info->baseType != UNIFORM_SAMPLER && info->baseType != UNIFORM_STORAGETEXTURE)
|
||||
if (info->location < 0)
|
||||
return;
|
||||
|
||||
if (current == this)
|
||||
Graphics::flushBatchedDrawsGlobal();
|
||||
int bindingindex = info->location + i;
|
||||
if (bindingindex < 0)
|
||||
return;
|
||||
|
||||
count = std::min(count, info->count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
auto &binding = textureBindings[bindingindex];
|
||||
if (isdefault && (binding.access & ACCESS_WRITE) != 0)
|
||||
{
|
||||
love::graphics::Texture *tex = textures[i];
|
||||
bool isdefault = tex == nullptr;
|
||||
|
||||
if (tex != nullptr)
|
||||
{
|
||||
if (!validateTexture(info, tex, false))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto gfx = Graphics::getInstance();
|
||||
tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType, info->isDepthSampler);
|
||||
}
|
||||
|
||||
tex->retain();
|
||||
|
||||
int resourceindex = info->resourceIndex + i;
|
||||
|
||||
if (activeTextures[resourceindex] != nullptr)
|
||||
activeTextures[resourceindex]->release();
|
||||
|
||||
activeTextures[resourceindex] = tex;
|
||||
|
||||
if (info->location < 0)
|
||||
continue;
|
||||
|
||||
int bindingindex = info->location + i;
|
||||
if (bindingindex < 0)
|
||||
continue;
|
||||
|
||||
auto &binding = textureBindings[bindingindex];
|
||||
if (isdefault && (binding.access & ACCESS_WRITE) != 0)
|
||||
{
|
||||
binding.texture = nil;
|
||||
binding.samplerTexture = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
binding.texture = getMTLTexture(tex);
|
||||
binding.samplerTexture = tex;
|
||||
}
|
||||
binding.texture = nil;
|
||||
binding.samplerTexture = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
binding.texture = getMTLTexture(texture);
|
||||
binding.samplerTexture = texture;
|
||||
}
|
||||
}}
|
||||
|
||||
void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count)
|
||||
{
|
||||
bool texelbinding = info->baseType == UNIFORM_TEXELBUFFER;
|
||||
bool storagebinding = info->baseType == UNIFORM_STORAGEBUFFER;
|
||||
|
||||
if (!texelbinding && !storagebinding)
|
||||
void Shader::applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType basetype, bool isdefault)
|
||||
{ @autoreleasepool {
|
||||
if (info->location < 0)
|
||||
return;
|
||||
|
||||
if (current == this)
|
||||
Graphics::flushBatchedDrawsGlobal();
|
||||
|
||||
count = std::min(count, info->count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
int bindingindex = info->location + i;
|
||||
if (basetype == UNIFORM_TEXELBUFFER && bindingindex >= 0)
|
||||
{
|
||||
love::graphics::Buffer *buffer = buffers[i];
|
||||
bool isdefault = buffer == nullptr;
|
||||
|
||||
if (buffer != nullptr)
|
||||
{
|
||||
if (!validateBuffer(info, buffer, false))
|
||||
continue;
|
||||
}
|
||||
textureBindings[bindingindex].texture = getMTLTexture(buffer);
|
||||
}
|
||||
else if (basetype == UNIFORM_STORAGEBUFFER && bindingindex >= 0)
|
||||
{
|
||||
auto &binding = bufferBindings[bindingindex];
|
||||
if (isdefault && (binding.access & ACCESS_WRITE) != 0)
|
||||
binding.buffer = nil;
|
||||
else
|
||||
{
|
||||
auto gfx = Graphics::getInstance();
|
||||
if (texelbinding)
|
||||
buffer = gfx->getDefaultTexelBuffer(info->dataBaseType);
|
||||
else
|
||||
buffer = gfx->getDefaultStorageBuffer();
|
||||
}
|
||||
|
||||
buffer->retain();
|
||||
|
||||
int resourceindex = info->resourceIndex + i;
|
||||
|
||||
if (activeBuffers[resourceindex] != nullptr)
|
||||
activeBuffers[resourceindex]->release();
|
||||
|
||||
activeBuffers[resourceindex] = buffer;
|
||||
|
||||
if (info->location < 0)
|
||||
continue;
|
||||
|
||||
int bindingindex = info->location + i;
|
||||
if (texelbinding && bindingindex >= 0)
|
||||
{
|
||||
textureBindings[bindingindex].texture = getMTLTexture(buffer);
|
||||
}
|
||||
else if (storagebinding && bindingindex >= 0)
|
||||
{
|
||||
auto &binding = bufferBindings[bindingindex];
|
||||
if (isdefault && (binding.access & ACCESS_WRITE) != 0)
|
||||
binding.buffer = nil;
|
||||
else
|
||||
binding.buffer = getMTLBuffer(buffer);
|
||||
}
|
||||
binding.buffer = getMTLBuffer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture)
|
||||
{
|
||||
const BuiltinUniform builtins[3] = {
|
||||
BUILTIN_TEXTURE_VIDEO_Y,
|
||||
BUILTIN_TEXTURE_VIDEO_CB,
|
||||
BUILTIN_TEXTURE_VIDEO_CR,
|
||||
};
|
||||
|
||||
love::graphics::Texture *textures[3] = {ytexture, cbtexture, crtexture};
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
const UniformInfo *info = builtinUniformInfo[builtins[i]];
|
||||
if (info != nullptr)
|
||||
sendTextures(info, &textures[i], 1);
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
id<MTLRenderPipelineState> Shader::getCachedRenderPipeline(graphics::Graphics *gfx, const RenderPipelineKey &key)
|
||||
{
|
||||
|
||||
@@ -553,170 +553,76 @@ void Shader::updateUniform(const UniformInfo *info, int count, bool internalupda
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count)
|
||||
void Shader::applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType basetype, bool isdefault)
|
||||
{
|
||||
Shader::sendTextures(info, textures, count, false);
|
||||
}
|
||||
|
||||
void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count, bool internalUpdate)
|
||||
{
|
||||
bool issampler = info->baseType == UNIFORM_SAMPLER;
|
||||
bool isstoragetex = info->baseType == UNIFORM_STORAGETEXTURE;
|
||||
|
||||
if (!issampler && !isstoragetex)
|
||||
return;
|
||||
|
||||
bool shaderactive = current == this;
|
||||
|
||||
if (!internalUpdate && shaderactive)
|
||||
flushBatchedDraws();
|
||||
|
||||
count = std::min(count, info->count);
|
||||
|
||||
// Bind the textures to the texture units.
|
||||
for (int i = 0; i < count; i++)
|
||||
if (basetype == UNIFORM_STORAGETEXTURE)
|
||||
{
|
||||
love::graphics::Texture *tex = textures[i];
|
||||
bool isdefault = tex == nullptr;
|
||||
GLuint gltex = (GLuint) texture->getHandle();
|
||||
|
||||
if (tex != nullptr)
|
||||
int bindingindex = info->ints[i];
|
||||
auto &binding = storageTextureBindings[bindingindex];
|
||||
|
||||
if (isdefault && (info->access & ACCESS_WRITE) != 0)
|
||||
{
|
||||
if (!validateTexture(info, tex, internalUpdate))
|
||||
continue;
|
||||
binding.texture = nullptr;
|
||||
binding.gltexture = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto gfx = Module::getInstance<love::graphics::Graphics>(Module::M_GRAPHICS);
|
||||
tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType, info->isDepthSampler);
|
||||
}
|
||||
|
||||
tex->retain();
|
||||
|
||||
int resourceindex = info->resourceIndex + i;
|
||||
|
||||
if (activeTextures[resourceindex] != nullptr)
|
||||
activeTextures[resourceindex]->release();
|
||||
|
||||
activeTextures[resourceindex] = tex;
|
||||
|
||||
if (isstoragetex)
|
||||
{
|
||||
GLuint gltex = (GLuint) tex->getHandle();
|
||||
|
||||
int bindingindex = info->ints[i];
|
||||
auto &binding = storageTextureBindings[bindingindex];
|
||||
|
||||
if (isdefault && (info->access & ACCESS_WRITE) != 0)
|
||||
{
|
||||
binding.texture = nullptr;
|
||||
binding.gltexture = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
binding.texture = tex;
|
||||
binding.gltexture = gltex;
|
||||
|
||||
if (shaderactive)
|
||||
glBindImageTexture(bindingindex, binding.gltexture, 0, GL_TRUE, 0, binding.access, binding.internalFormat);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GLuint gltex = (GLuint) tex->getHandle();
|
||||
|
||||
int texunit = info->ints[i];
|
||||
binding.texture = texture;
|
||||
binding.gltexture = gltex;
|
||||
|
||||
if (shaderactive)
|
||||
gl.bindTextureToUnit(info->textureType, gltex, texunit, false, false);
|
||||
|
||||
// Store texture id so it can be re-bound to the texture unit later.
|
||||
textureUnits[texunit].texture = gltex;
|
||||
glBindImageTexture(bindingindex, binding.gltexture, 0, GL_TRUE, 0, binding.access, binding.internalFormat);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GLuint gltex = (GLuint) texture->getHandle();
|
||||
|
||||
int texunit = info->ints[i];
|
||||
|
||||
if (shaderactive)
|
||||
gl.bindTextureToUnit(info->textureType, gltex, texunit, false, false);
|
||||
|
||||
// Store texture id so it can be re-bound to the texture unit later.
|
||||
textureUnits[texunit].texture = gltex;
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count)
|
||||
void Shader::applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType basetype, bool isdefault)
|
||||
{
|
||||
Shader::sendBuffers(info, buffers, count, false);
|
||||
}
|
||||
|
||||
void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count, bool internalUpdate)
|
||||
{
|
||||
bool texelbinding = info->baseType == UNIFORM_TEXELBUFFER;
|
||||
bool storagebinding = info->baseType == UNIFORM_STORAGEBUFFER;
|
||||
|
||||
if (!texelbinding && !storagebinding)
|
||||
return;
|
||||
|
||||
bool shaderactive = current == this;
|
||||
|
||||
if (!internalUpdate && shaderactive)
|
||||
flushBatchedDraws();
|
||||
|
||||
count = std::min(count, info->count);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
if (basetype == UNIFORM_TEXELBUFFER)
|
||||
{
|
||||
love::graphics::Buffer *buffer = buffers[i];
|
||||
bool isdefault = buffer == nullptr;
|
||||
GLuint gltex = (GLuint) buffer->getTexelBufferHandle();
|
||||
int texunit = info->ints[i];
|
||||
|
||||
if (buffer != nullptr)
|
||||
{
|
||||
if (!validateBuffer(info, buffer, internalUpdate))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto gfx = Module::getInstance<love::graphics::Graphics>(Module::M_GRAPHICS);
|
||||
if (texelbinding)
|
||||
buffer = gfx->getDefaultTexelBuffer(info->dataBaseType);
|
||||
else
|
||||
buffer = gfx->getDefaultStorageBuffer();
|
||||
}
|
||||
if (shaderactive)
|
||||
gl.bindBufferTextureToUnit(gltex, texunit, false, false);
|
||||
|
||||
buffer->retain();
|
||||
|
||||
int resourceindex = info->resourceIndex + i;
|
||||
|
||||
if (activeBuffers[resourceindex] != nullptr)
|
||||
activeBuffers[resourceindex]->release();
|
||||
|
||||
activeBuffers[resourceindex] = buffer;
|
||||
|
||||
if (texelbinding)
|
||||
{
|
||||
GLuint gltex = (GLuint) buffer->getTexelBufferHandle();
|
||||
int texunit = info->ints[i];
|
||||
|
||||
if (shaderactive)
|
||||
gl.bindBufferTextureToUnit(gltex, texunit, false, false);
|
||||
|
||||
// Store texture id so it can be re-bound to the texture unit later.
|
||||
textureUnits[texunit].texture = gltex;
|
||||
}
|
||||
else if (storagebinding)
|
||||
{
|
||||
GLuint glbuffer = (GLuint)buffer->getHandle();
|
||||
int bindingindex = info->ints[i];
|
||||
|
||||
if (shaderactive)
|
||||
gl.bindIndexedBuffer(glbuffer, BUFFERUSAGE_SHADER_STORAGE, bindingindex);
|
||||
|
||||
auto activeindex = storageBufferBindingIndexToActiveBinding[bindingindex];
|
||||
|
||||
if (activeindex.first >= 0)
|
||||
activeStorageBufferBindings[activeindex.first].buffer = glbuffer;
|
||||
|
||||
if (activeindex.second >= 0)
|
||||
activeWritableStorageBuffers[activeindex.second] = isdefault ? nullptr : buffer;
|
||||
}
|
||||
// Store texture id so it can be re-bound to the texture unit later.
|
||||
textureUnits[texunit].texture = gltex;
|
||||
}
|
||||
}
|
||||
else if (basetype == UNIFORM_STORAGEBUFFER)
|
||||
{
|
||||
GLuint glbuffer = (GLuint)buffer->getHandle();
|
||||
int bindingindex = info->ints[i];
|
||||
|
||||
void Shader::flushBatchedDraws() const
|
||||
{
|
||||
if (current == this)
|
||||
Graphics::flushBatchedDrawsGlobal();
|
||||
if (shaderactive)
|
||||
gl.bindIndexedBuffer(glbuffer, BUFFERUSAGE_SHADER_STORAGE, bindingindex);
|
||||
|
||||
auto activeindex = storageBufferBindingIndexToActiveBinding[bindingindex];
|
||||
|
||||
if (activeindex.first >= 0)
|
||||
activeStorageBufferBindings[activeindex.first].buffer = glbuffer;
|
||||
|
||||
if (activeindex.second >= 0)
|
||||
activeWritableStorageBuffers[activeindex.second] = isdefault ? nullptr : buffer;
|
||||
}
|
||||
}
|
||||
|
||||
ptrdiff_t Shader::getHandle() const
|
||||
@@ -736,25 +642,6 @@ int Shader::getVertexAttributeIndex(const std::string &name)
|
||||
return location;
|
||||
}
|
||||
|
||||
void Shader::setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture)
|
||||
{
|
||||
const BuiltinUniform builtins[3] = {
|
||||
BUILTIN_TEXTURE_VIDEO_Y,
|
||||
BUILTIN_TEXTURE_VIDEO_CB,
|
||||
BUILTIN_TEXTURE_VIDEO_CR,
|
||||
};
|
||||
|
||||
love::graphics::Texture *textures[3] = {ytexture, cbtexture, crtexture};
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
const UniformInfo *info = builtinUniformInfo[builtins[i]];
|
||||
|
||||
if (info != nullptr)
|
||||
sendTextures(info, &textures[i], 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, int viewportH)
|
||||
{
|
||||
if (current != this)
|
||||
|
||||
@@ -65,10 +65,7 @@ public:
|
||||
int getVertexAttributeIndex(const std::string &name) override;
|
||||
const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override;
|
||||
void updateUniform(const UniformInfo *info, int count) override;
|
||||
void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override;
|
||||
void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override;
|
||||
ptrdiff_t getHandle() const override;
|
||||
void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override;
|
||||
|
||||
void updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, int viewportH);
|
||||
|
||||
@@ -95,10 +92,9 @@ private:
|
||||
void mapActiveUniforms();
|
||||
|
||||
void updateUniform(const UniformInfo *info, int count, bool internalupdate);
|
||||
void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count, bool internalupdate);
|
||||
void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count, bool internalupdate);
|
||||
|
||||
void flushBatchedDraws() const;
|
||||
void applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType basetype, bool isdefault) override;
|
||||
void applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType basetype, bool isdefault) override;
|
||||
|
||||
// Get any warnings or errors generated only by the shader program object.
|
||||
std::string getProgramWarnings() const;
|
||||
|
||||
@@ -367,83 +367,14 @@ void Shader::updateUniform(const UniformInfo *info, int count)
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count)
|
||||
void Shader::applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType /*basetype*/, bool isdefault)
|
||||
{
|
||||
bool issampler = info->baseType == UNIFORM_SAMPLER;
|
||||
bool isstoragetex = info->baseType == UNIFORM_STORAGETEXTURE;
|
||||
|
||||
count = std::min(count, info->count);
|
||||
|
||||
if (current == this)
|
||||
Graphics::flushBatchedDrawsGlobal();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
love::graphics::Texture *tex = textures[i];
|
||||
bool isdefault = tex == nullptr;
|
||||
|
||||
if (tex != nullptr)
|
||||
{
|
||||
if (!validateTexture(info, tex, false))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto gfx = Module::getInstance<love::graphics::Graphics>(Module::M_GRAPHICS);
|
||||
tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType, info->isDepthSampler);
|
||||
}
|
||||
|
||||
int resourceindex = info->resourceIndex + i;
|
||||
auto prevtexture = activeTextures[resourceindex];
|
||||
activeTextures[resourceindex] = tex;
|
||||
activeTextures[resourceindex]->retain();
|
||||
if (prevtexture)
|
||||
prevtexture->release();
|
||||
|
||||
if (tex != prevtexture)
|
||||
setTextureDescriptor(info, (isdefault && (info->access & ACCESS_WRITE) != 0) ? nullptr : tex, i);
|
||||
}
|
||||
setTextureDescriptor(info, (isdefault && (info->access & ACCESS_WRITE) != 0) ? nullptr : texture, i);
|
||||
}
|
||||
|
||||
void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count)
|
||||
void Shader::applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType /*basetype*/, bool isdefault)
|
||||
{
|
||||
bool texelbinding = info->baseType == UNIFORM_TEXELBUFFER;
|
||||
bool storagebinding = info->baseType == UNIFORM_STORAGEBUFFER;
|
||||
|
||||
count = std::min(count, info->count);
|
||||
|
||||
if (current == this)
|
||||
Graphics::flushBatchedDrawsGlobal();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
love::graphics::Buffer *buffer = buffers[i];
|
||||
bool isdefault = buffer == nullptr;
|
||||
|
||||
if (buffer != nullptr)
|
||||
{
|
||||
if (!validateBuffer(info, buffer, false))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto gfx = Module::getInstance<love::graphics::Graphics>(Module::M_GRAPHICS);
|
||||
if (texelbinding)
|
||||
buffer = gfx->getDefaultTexelBuffer(info->dataBaseType);
|
||||
else
|
||||
buffer = gfx->getDefaultStorageBuffer();
|
||||
}
|
||||
|
||||
int resourceindex = info->resourceIndex + i;
|
||||
auto prevbuffer = activeBuffers[resourceindex];
|
||||
activeBuffers[resourceindex] = buffer;
|
||||
activeBuffers[resourceindex]->retain();
|
||||
if (prevbuffer)
|
||||
prevbuffer->release();
|
||||
|
||||
if (buffer != prevbuffer)
|
||||
setBufferDescriptor(info, (isdefault && (info->access & ACCESS_WRITE) != 0) ? nullptr : buffer, i);
|
||||
}
|
||||
setBufferDescriptor(info, (isdefault && (info->access & ACCESS_WRITE) != 0) ? nullptr : buffer, i);
|
||||
}
|
||||
|
||||
void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename)
|
||||
@@ -1078,37 +1009,6 @@ void Shader::createDescriptorPoolSizes()
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture)
|
||||
{
|
||||
std::array<graphics::Texture*, 3> textures = {
|
||||
ytexture, cbtexture, crtexture
|
||||
};
|
||||
|
||||
std::array<BuiltinUniform, 3> builtIns = {
|
||||
BUILTIN_TEXTURE_VIDEO_Y,
|
||||
BUILTIN_TEXTURE_VIDEO_CB,
|
||||
BUILTIN_TEXTURE_VIDEO_CR,
|
||||
};
|
||||
|
||||
static_assert(textures.size() == builtIns.size(), "expected number of textures to be the same");
|
||||
|
||||
for (size_t i = 0; i < textures.size(); i++)
|
||||
{
|
||||
const UniformInfo *u = builtinUniformInfo[builtIns[i]];
|
||||
if (u != nullptr)
|
||||
{
|
||||
auto prevtexture = activeTextures[u->resourceIndex];
|
||||
textures[i]->retain();
|
||||
if (prevtexture)
|
||||
prevtexture->release();
|
||||
activeTextures[u->resourceIndex] = textures[i];
|
||||
|
||||
if (textures[i] != prevtexture)
|
||||
setTextureDescriptor(u, textures[i], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::setMainTex(graphics::Texture *texture)
|
||||
{
|
||||
const UniformInfo *u = builtinUniformInfo[BUILTIN_TEXTURE_MAIN];
|
||||
@@ -1134,10 +1034,13 @@ void Shader::setTextureDescriptor(const UniformInfo *info, love::graphics::Textu
|
||||
|
||||
// Samplers may change after this call, so they're set just before the
|
||||
// descriptor set is used instead of here.
|
||||
imageInfo.imageLayout = vkTexture != nullptr ? vkTexture->getImageLayout() : VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.imageView = vkTexture != nullptr ? (VkImageView)vkTexture->getRenderTargetHandle() : VK_NULL_HANDLE;
|
||||
|
||||
resourceDescriptorsDirty = true;
|
||||
VkImageView view = vkTexture != nullptr ? (VkImageView)vkTexture->getRenderTargetHandle() : VK_NULL_HANDLE;
|
||||
if (view != imageInfo.imageView)
|
||||
{
|
||||
imageInfo.imageLayout = vkTexture != nullptr ? vkTexture->getImageLayout() : VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.imageView = view;
|
||||
resourceDescriptorsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Shader::setBufferDescriptor(const UniformInfo *info, love::graphics::Buffer *buffer, int index)
|
||||
@@ -1145,16 +1048,25 @@ void Shader::setBufferDescriptor(const UniformInfo *info, love::graphics::Buffer
|
||||
if (info->baseType == UNIFORM_STORAGEBUFFER)
|
||||
{
|
||||
VkDescriptorBufferInfo &bufferInfo = descriptorBuffers[info->bindingStartIndex + index];
|
||||
bufferInfo.buffer = buffer != nullptr ? (VkBuffer)buffer->getHandle() : VK_NULL_HANDLE;
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.range = buffer != nullptr ? buffer->getSize() : 0;
|
||||
VkBuffer vkbuffer = buffer != nullptr ? (VkBuffer)buffer->getHandle() : VK_NULL_HANDLE;
|
||||
VkDeviceSize range = buffer != nullptr ? buffer->getSize() : 0;
|
||||
if (vkbuffer != bufferInfo.buffer || bufferInfo.offset != 0 || range != bufferInfo.range)
|
||||
{
|
||||
bufferInfo.buffer = vkbuffer;
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.range = range;
|
||||
resourceDescriptorsDirty = true;
|
||||
}
|
||||
}
|
||||
else if (info->baseType == UNIFORM_TEXELBUFFER)
|
||||
{
|
||||
descriptorBufferViews[info->bindingStartIndex + index] = buffer != nullptr ? (VkBufferView)buffer->getTexelBufferHandle() : VK_NULL_HANDLE;
|
||||
VkBufferView view = buffer != nullptr ? (VkBufferView)buffer->getTexelBufferHandle() : VK_NULL_HANDLE;
|
||||
if (view != descriptorBufferViews[info->bindingStartIndex + index])
|
||||
{
|
||||
descriptorBufferViews[info->bindingStartIndex + index] = view;
|
||||
resourceDescriptorsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
resourceDescriptorsDirty = true;
|
||||
}
|
||||
|
||||
void Shader::createDescriptorPool()
|
||||
|
||||
@@ -153,11 +153,6 @@ public:
|
||||
|
||||
void updateUniform(const UniformInfo *info, int count) override;
|
||||
|
||||
void sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) override;
|
||||
void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override;
|
||||
|
||||
void setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture) override;
|
||||
|
||||
void setMainTex(graphics::Texture *texture);
|
||||
|
||||
VkPipeline getCachedGraphicsPipeline(Graphics *vgfx, const GraphicsPipelineConfigurationCore &configuration);
|
||||
@@ -175,6 +170,9 @@ private:
|
||||
void setTextureDescriptor(const UniformInfo *info, love::graphics::Texture *texture, int index);
|
||||
void setBufferDescriptor(const UniformInfo *info, love::graphics::Buffer *buffer, int index);
|
||||
|
||||
void applyTexture(const UniformInfo *info, int i, love::graphics::Texture *texture, UniformType basetype, bool isdefault) override;
|
||||
void applyBuffer(const UniformInfo *info, int i, love::graphics::Buffer *buffer, UniformType basetype, bool isdefault) override;
|
||||
|
||||
VkPipeline computePipeline = VK_NULL_HANDLE;
|
||||
|
||||
VkDescriptorSetLayout descriptorSetLayout = VK_NULL_HANDLE;
|
||||
|
||||
Reference in New Issue
Block a user