Skip to content

Commit

Permalink
graphics: handle default textures in high level code.
Browse files Browse the repository at this point in the history
Previously each backend had to set up default textures with its own code, which needs some care for it to be robust.
  • Loading branch information
slime73 committed Dec 27, 2023
1 parent e42019c commit 8872497
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 189 deletions.
99 changes: 93 additions & 6 deletions src/modules/graphics/Graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ Graphics::Graphics()
, quadIndexBuffer(nullptr)
, fanIndexBuffer(nullptr)
, capabilities()
, defaultTextures()
, cachedShaderStages()
{
transformStack.reserve(16);
Expand All @@ -217,6 +218,8 @@ Graphics::~Graphics()
if (fanIndexBuffer != nullptr)
fanIndexBuffer->release();

releaseDefaultResources();

// Clean up standard shaders before the active shader. If we do it after,
// the active shader may try to activate a standard shader when deactivating
// itself, which will cause problems since it calls Graphics methods in the
Expand Down Expand Up @@ -530,6 +533,90 @@ bool Graphics::validateShader(bool gles, const std::vector<std::string> &stagess
return Shader::validate(stages, err);
}

Texture *Graphics::getDefaultTexture(TextureType type, DataBaseType dataType)
{
Texture *tex = defaultTextures[type][dataType];
if (tex != nullptr)
return tex;

Texture::Settings settings;
settings.type = type;

switch (dataType)
{
case DATA_BASETYPE_INT:
settings.format = PIXELFORMAT_RGBA8_INT;
break;
case DATA_BASETYPE_UINT:
settings.format = PIXELFORMAT_RGBA8_UINT;
break;
case DATA_BASETYPE_FLOAT:
default:
settings.format = PIXELFORMAT_RGBA8_UNORM;
break;
}

std::string name = "default_";

const char *tname = "unknown";
Texture::getConstant(type, tname);
name += tname;

const char *formatname = "unknown";
love::getConstant(settings.format, formatname);
name += std::string("_") + formatname;

settings.debugName = name;

tex = newTexture(settings);

SamplerState s;
s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST;
s.wrapU = s.wrapV = s.wrapW = SamplerState::WRAP_CLAMP;
tex->setSamplerState(s);

uint8 pixel[] = {255, 255, 255, 255};
if (isPixelFormatInteger(settings.format))
pixel[0] = pixel[1] = pixel[2] = pixel[3] = 1;

for (int slice = 0; slice < (type == TEXTURE_CUBE ? 6 : 1); slice++)
tex->replacePixels(pixel, sizeof(pixel), slice, 0, {0, 0, 1, 1}, false);

defaultTextures[type][dataType] = tex;

return tex;
}

void Graphics::releaseDefaultResources()
{
for (int type = 0; type < TEXTURE_MAX_ENUM; type++)
{
for (int dataType = 0; dataType < DATA_BASETYPE_MAX_ENUM; dataType++)
{
if (defaultTextures[type][dataType])
defaultTextures[type][dataType]->release();
defaultTextures[type][dataType] = nullptr;
}
}
}

Texture *Graphics::getTextureOrDefaultForActiveShader(Texture *tex)
{
if (tex != nullptr)
return tex;

Shader *shader = Shader::current;

if (shader != nullptr)
{
auto texinfo = shader->getMainTextureInfo();
if (texinfo != nullptr && texinfo->textureType != TEXTURE_MAX_ENUM)
return getDefaultTexture(texinfo->textureType, texinfo->dataBaseType);
}

return getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT);
}

int Graphics::getWidth() const
{
return width;
Expand Down Expand Up @@ -1825,7 +1912,7 @@ void Graphics::flushBatchedDraws()
cmd.indexCount = sbstate.indexCount;
cmd.indexType = INDEX_UINT16;
cmd.indexBufferOffset = sbstate.indexBuffer->unmap(usedsizes[2]);
cmd.texture = sbstate.texture;
cmd.texture = getTextureOrDefaultForActiveShader(sbstate.texture);
draw(cmd);

sbstate.indexBufferMap = StreamBuffer::MapInfo();
Expand All @@ -1836,7 +1923,7 @@ void Graphics::flushBatchedDraws()
cmd.primitiveType = sbstate.primitiveMode;
cmd.vertexStart = 0;
cmd.vertexCount = sbstate.vertexCount;
cmd.texture = sbstate.texture;
cmd.texture = getTextureOrDefaultForActiveShader(sbstate.texture);
draw(cmd);
}

Expand Down Expand Up @@ -1933,7 +2020,7 @@ void Graphics::drawFromShader(PrimitiveType primtype, int vertexcount, int insta
cmd.primitiveType = primtype;
cmd.vertexCount = vertexcount;
cmd.instanceCount = std::max(1, instancecount);
cmd.texture = maintexture;
cmd.texture = getTextureOrDefaultForActiveShader(maintexture);

draw(cmd);
}
Expand Down Expand Up @@ -1974,7 +2061,7 @@ void Graphics::drawFromShader(Buffer *indexbuffer, int indexcount, int instancec
cmd.indexType = getIndexDataType(indexbuffer->getDataMember(0).decl.format);
cmd.indexBufferOffset = startindex * getIndexDataSize(cmd.indexType);

cmd.texture = maintexture;
cmd.texture = getTextureOrDefaultForActiveShader(maintexture);

draw(cmd);
}
Expand All @@ -2001,7 +2088,7 @@ void Graphics::drawFromShaderIndirect(PrimitiveType primtype, Buffer *indirectar
cmd.primitiveType = primtype;
cmd.indirectBuffer = indirectargs;
cmd.indirectBufferOffset = argsindex * indirectargs->getArrayStride();
cmd.texture = maintexture;
cmd.texture = getTextureOrDefaultForActiveShader(maintexture);

draw(cmd);
}
Expand Down Expand Up @@ -2029,7 +2116,7 @@ void Graphics::drawFromShaderIndirect(Buffer *indexbuffer, Buffer *indirectargs,
cmd.indexType = getIndexDataType(indexbuffer->getDataMember(0).decl.format);
cmd.indirectBuffer = indirectargs;
cmd.indexBufferOffset = argsindex * indirectargs->getArrayStride();
cmd.texture = maintexture;
cmd.texture = getTextureOrDefaultForActiveShader(maintexture);

draw(cmd);
}
Expand Down
7 changes: 7 additions & 0 deletions src/modules/graphics/Graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,9 @@ class Graphics : public Module

bool validateShader(bool gles, const std::vector<std::string> &stages, const Shader::CompileOptions &options, std::string &err);

Texture *getDefaultTexture(TextureType type, DataBaseType dataType);
Texture *getTextureOrDefaultForActiveShader(Texture *tex);

/**
* Resets the current color, background color, line style, and so forth.
**/
Expand Down Expand Up @@ -1039,6 +1042,8 @@ class Graphics : public Module

void updatePendingReadbacks();

void releaseDefaultResources();

void restoreState(const DisplayState &s);
void restoreStateChecked(const DisplayState &s);

Expand Down Expand Up @@ -1094,6 +1099,8 @@ class Graphics : public Module
void checkSetDefaultFont();
int calculateEllipsePoints(float rx, float ry) const;

Texture *defaultTextures[TEXTURE_MAX_ENUM][DATA_BASETYPE_MAX_ENUM];

std::vector<uint8> scratchBuffer;

std::unordered_map<std::string, ShaderStage *> cachedShaderStages[SHADERSTAGE_MAX_ENUM];
Expand Down
4 changes: 2 additions & 2 deletions src/modules/graphics/Mesh.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,7 @@ void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buff
cmd.primitiveType = primitiveType;
cmd.indexType = indexDataType;
cmd.instanceCount = instancecount;
cmd.texture = texture;
cmd.texture = gfx->getTextureOrDefaultForActiveShader(texture);
cmd.cullMode = gfx->getMeshCullMode();

cmd.indexBufferOffset = r.getOffset() * indexbuffer->getArrayStride();
Expand All @@ -691,7 +691,7 @@ void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buff
cmd.vertexStart = (int) r.getOffset();
cmd.vertexCount = (int) r.getSize();
cmd.instanceCount = instancecount;
cmd.texture = texture;
cmd.texture = gfx->getTextureOrDefaultForActiveShader(texture);
cmd.cullMode = gfx->getMeshCullMode();

cmd.indirectBuffer = indirectargs;
Expand Down
3 changes: 2 additions & 1 deletion src/modules/graphics/ParticleSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1086,7 +1086,8 @@ void ParticleSystem::draw(Graphics *gfx, const Matrix4 &m)
BufferBindings vertexbuffers;
vertexbuffers.set(0, buffer, 0);

gfx->drawQuads(0, pCount, vertexAttributes, vertexbuffers, texture);
Texture *tex = gfx->getTextureOrDefaultForActiveShader(texture);
gfx->drawQuads(0, pCount, vertexAttributes, vertexbuffers, tex);
}

bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out)
Expand Down
5 changes: 4 additions & 1 deletion src/modules/graphics/SpriteBatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,10 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m)
count = std::min(count, next - start);

if (count > 0)
gfx->drawQuads(start, count, attributes, buffers, texture);
{
Texture *tex = gfx->getTextureOrDefaultForActiveShader(texture);
gfx->drawQuads(start, count, attributes, buffers, tex);
}
}

} // graphics
Expand Down
5 changes: 4 additions & 1 deletion src/modules/graphics/TextBatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,10 @@ void TextBatch::draw(Graphics *gfx, const Matrix4 &m)
Graphics::TempTransform transform(gfx, m);

for (const Font::DrawCommand &cmd : drawCommands)
gfx->drawQuads(cmd.startvertex / 4, cmd.vertexcount / 4, vertexAttributes, vertexBuffers, cmd.texture);
{
Texture *tex = gfx->getTextureOrDefaultForActiveShader(cmd.texture);
gfx->drawQuads(cmd.startvertex / 4, cmd.vertexcount / 4, vertexAttributes, vertexBuffers, tex);
}
}

} // graphics
Expand Down
3 changes: 0 additions & 3 deletions src/modules/graphics/metal/Graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,6 @@ class Graphics final : public love::graphics::Graphics

StreamBuffer *getUniformBuffer() const { return uniformBuffer; }
Buffer *getDefaultAttributesBuffer() const { return defaultAttributesBuffer; }
Texture *getDefaultTexture(TextureType textype) const { return defaultTextures[textype]; }

int getClosestMSAASamples(int requestedsamples);

Expand Down Expand Up @@ -247,8 +246,6 @@ class Graphics final : public love::graphics::Graphics

Buffer *defaultAttributesBuffer;

Texture *defaultTextures[TEXTURE_MAX_ENUM];

std::map<uint64, void *> cachedSamplers;
std::unordered_map<uint64, void *> cachedDepthStencilStates;

Expand Down
22 changes: 0 additions & 22 deletions src/modules/graphics/metal/Graphics.mm
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@ static inline void setSampler(id<MTLComputeCommandEncoder> encoder, Graphics::Re
, renderBindings()
, uniformBufferOffset(0)
, defaultAttributesBuffer(nullptr)
, defaultTextures()
, families()
{ @autoreleasepool {
if (@available(macOS 10.15, iOS 13.0, *))
Expand Down Expand Up @@ -346,17 +345,6 @@ static inline void setSampler(id<MTLComputeCommandEncoder> encoder, Graphics::Re
defaultAttributesBuffer = newBuffer(attribsettings, dataformat, &defaults, sizeof(DefaultVertexAttributes), 0);
}

uint8 defaultpixel[] = {255, 255, 255, 255};
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
{
Texture::Settings settings;
settings.type = (TextureType) i;
settings.format = PIXELFORMAT_RGBA8_UNORM;
defaultTextures[i] = newTexture(settings);
Rect r = {0, 0, 1, 1};
defaultTextures[i]->replacePixels(defaultpixel, sizeof(defaultpixel), 0, 0, r, false);
}

if (batchedDrawState.vb[0] == nullptr)
{
// Initial sizes that should be good enough for most cases. It will
Expand Down Expand Up @@ -426,9 +414,6 @@ static inline void setSampler(id<MTLComputeCommandEncoder> encoder, Graphics::Re
commandQueue = nil;
device = nil;

for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
defaultTextures[i]->release();

for (auto &kvp : cachedSamplers)
CFBridgingRelease(kvp.second);

Expand Down Expand Up @@ -1144,13 +1129,6 @@ static bool isClampOne(SamplerState::WrapMode w)

if (b.isMainTexture)
{
if (maintex == nullptr)
{
auto texinfo = shader->getMainTextureInfo();
if (texinfo != nullptr && texinfo->textureType != TEXTURE_MAX_ENUM)
maintex = defaultTextures[texinfo->textureType];
}

texture = getMTLTexture(maintex);
samplertex = maintex;
}
Expand Down
13 changes: 10 additions & 3 deletions src/modules/graphics/metal/Shader.mm
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ static EShLanguage getGLSLangStage(ShaderStageType stage)

if (u.baseType == UNIFORM_SAMPLER)
{
auto tex = Graphics::getInstance()->getDefaultTexture(u.textureType);
auto tex = Graphics::getInstance()->getDefaultTexture(u.textureType, u.dataBaseType);
for (int i = 0; i < u.count; i++)
{
tex->retain();
Expand All @@ -538,8 +538,15 @@ static EShLanguage getGLSLangStage(ShaderStageType stage)
}
else if (u.baseType == UNIFORM_STORAGETEXTURE)
{
Texture *tex = nullptr;
if ((u.access & ACCESS_WRITE) == 0)
tex = Graphics::getInstance()->getDefaultTexture(u.textureType, u.dataBaseType);
for (int i = 0; i < u.count; i++)
u.textures[i] = nullptr;
{
if (tex)
tex->retain();
u.textures[i] = tex;
}
}

uniforms[u.name] = u;
Expand Down Expand Up @@ -983,7 +990,7 @@ static EShLanguage getGLSLangStage(ShaderStageType stage)
else
{
auto gfx = Graphics::getInstance();
tex = gfx->getDefaultTexture(info->textureType);
tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType);
}

tex->retain();
Expand Down
5 changes: 4 additions & 1 deletion src/modules/graphics/opengl/Graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1765,7 +1765,10 @@ uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable)
// Make sure at least something is bound to a color attachment. I believe
// this is required on ES2 but I'm not positive.
if (isPixelFormatDepthStencil(format))
gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, gl.getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT), 0, 0, 0);
{
love::graphics::Texture *tex = getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT);
gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, (GLuint) tex->getHandle(), 0, 0, 0);
}

if (readable)
{
Expand Down
Loading

0 comments on commit 8872497

Please sign in to comment.