mirror of
https://github.com/love2d/love.git
synced 2026-08-20 04:30:09 +02:00
graphics: handle default textures in high level code.
Previously each backend had to set up default textures with its own code, which needs some care for it to be robust.
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -323,8 +323,6 @@ void OpenGL::setupContext()
|
||||
setStencilWriteMask(state.stencilWriteMask);
|
||||
setColorWriteMask(state.colorWriteMask);
|
||||
|
||||
createDefaultTexture();
|
||||
|
||||
contextInitialized = true;
|
||||
|
||||
#ifdef LOVE_ANDROID
|
||||
@@ -341,18 +339,6 @@ void OpenGL::deInitContext()
|
||||
if (!contextInitialized)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
|
||||
{
|
||||
for (int datatype = DATA_BASETYPE_FLOAT; datatype <= DATA_BASETYPE_UINT; datatype++)
|
||||
{
|
||||
if (state.defaultTexture[i][datatype] != 0)
|
||||
{
|
||||
gl.deleteTexture(state.defaultTexture[i][datatype]);
|
||||
state.defaultTexture[i][datatype] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contextInitialized = false;
|
||||
}
|
||||
|
||||
@@ -604,71 +590,6 @@ void OpenGL::initMaxValues()
|
||||
maxLODBias = 0.0f;
|
||||
}
|
||||
|
||||
void OpenGL::createDefaultTexture()
|
||||
{
|
||||
// Set the 'default' texture as a repeating white pixel. Otherwise, texture
|
||||
// calls inside a shader would return black when drawing graphics primitives
|
||||
// which would create the need to use different "passthrough" shaders for
|
||||
// untextured primitives vs images.
|
||||
const GLubyte pix[] = {255, 255, 255, 255};
|
||||
const GLubyte intpix[] = {1, 1, 1, 1};
|
||||
|
||||
SamplerState s;
|
||||
s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST;
|
||||
s.wrapU = s.wrapV = s.wrapW = SamplerState::WRAP_CLAMP;
|
||||
|
||||
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
|
||||
{
|
||||
for (int datatype = (int)DATA_BASETYPE_FLOAT; datatype <= (int)DATA_BASETYPE_UINT; datatype++)
|
||||
{
|
||||
state.defaultTexture[i][datatype] = 0;
|
||||
|
||||
TextureType type = (TextureType) i;
|
||||
|
||||
if (!isTextureTypeSupported(type))
|
||||
continue;
|
||||
|
||||
if (datatype != DATA_BASETYPE_FLOAT && !(GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0))
|
||||
continue;
|
||||
|
||||
GLuint curtexture = state.boundTextures[type][0];
|
||||
|
||||
glGenTextures(1, &state.defaultTexture[type][datatype]);
|
||||
bindTextureToUnit(type, state.defaultTexture[type][datatype], 0, false);
|
||||
|
||||
setSamplerState(type, s);
|
||||
|
||||
PixelFormat format = PIXELFORMAT_RGBA8_UNORM;
|
||||
if (datatype == DATA_BASETYPE_INT)
|
||||
format = PIXELFORMAT_RGBA8_INT;
|
||||
else if (datatype == DATA_BASETYPE_UINT)
|
||||
format = PIXELFORMAT_RGBA8_UINT;
|
||||
|
||||
const GLubyte *p = datatype == DATA_BASETYPE_FLOAT ? pix : intpix;
|
||||
|
||||
rawTexStorage(type, 1, format, 1, 1);
|
||||
|
||||
TextureFormat fmt = convertPixelFormat(format, false);
|
||||
int slices = type == TEXTURE_CUBE ? 6 : 1;
|
||||
|
||||
for (int slice = 0; slice < slices; slice++)
|
||||
{
|
||||
GLenum gltarget = getGLTextureType(type);
|
||||
|
||||
if (type == TEXTURE_CUBE)
|
||||
gltarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
|
||||
|
||||
if (type == TEXTURE_2D || type == TEXTURE_CUBE)
|
||||
glTexSubImage2D(gltarget, 0, 0, 0, 1, 1, fmt.externalformat, fmt.type, p);
|
||||
else if (type == TEXTURE_2D_ARRAY || type == TEXTURE_VOLUME)
|
||||
glTexSubImage3D(gltarget, 0, 0, 0, slice, 1, 1, 1, fmt.externalformat, fmt.type, p);
|
||||
}
|
||||
|
||||
bindTextureToUnit(type, curtexture, 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGL::prepareDraw(love::graphics::Graphics *gfx)
|
||||
{
|
||||
TempDebugGroup debuggroup("Prepare OpenGL draw");
|
||||
@@ -702,6 +623,7 @@ GLenum OpenGL::getGLBufferType(BufferUsage usage)
|
||||
case BUFFERUSAGE_VERTEX: return GL_ARRAY_BUFFER;
|
||||
case BUFFERUSAGE_INDEX: return GL_ELEMENT_ARRAY_BUFFER;
|
||||
case BUFFERUSAGE_TEXEL: return GL_TEXTURE_BUFFER;
|
||||
case BUFFERUSAGE_UNIFORM: return GL_UNIFORM_BUFFER;
|
||||
case BUFFERUSAGE_SHADER_STORAGE: return GL_SHADER_STORAGE_BUFFER;
|
||||
case BUFFERUSAGE_INDIRECT_ARGUMENTS: return GL_DRAW_INDIRECT_BUFFER;
|
||||
case BUFFERUSAGE_MAX_ENUM: return GL_ZERO;
|
||||
@@ -1191,11 +1113,6 @@ GLuint OpenGL::getDefaultFBO() const
|
||||
#endif
|
||||
}
|
||||
|
||||
GLuint OpenGL::getDefaultTexture(TextureType type, DataBaseType datatype) const
|
||||
{
|
||||
return state.defaultTexture[type][datatype];
|
||||
}
|
||||
|
||||
void OpenGL::setTextureUnit(int textureunit)
|
||||
{
|
||||
if (textureunit != state.curTextureUnit)
|
||||
@@ -1234,31 +1151,8 @@ void OpenGL::bindBufferTextureToUnit(GLuint texture, int textureunit, bool resto
|
||||
|
||||
void OpenGL::bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev, bool bindforedit)
|
||||
{
|
||||
TextureType textype = TEXTURE_2D;
|
||||
GLuint handle = 0;
|
||||
|
||||
if (texture != nullptr)
|
||||
{
|
||||
textype = texture->getTextureType();
|
||||
handle = (GLuint) texture->getHandle();
|
||||
}
|
||||
else
|
||||
{
|
||||
DataBaseType datatype = DATA_BASETYPE_FLOAT;
|
||||
|
||||
if (textureunit == 0 && Shader::current != nullptr)
|
||||
{
|
||||
const Shader::UniformInfo *info = Shader::current->getMainTextureInfo();
|
||||
if (info != nullptr)
|
||||
{
|
||||
textype = info->textureType;
|
||||
datatype = info->dataBaseType;
|
||||
}
|
||||
}
|
||||
|
||||
handle = getDefaultTexture(textype, datatype);
|
||||
}
|
||||
|
||||
TextureType textype = texture->getTextureType();
|
||||
GLuint handle = (GLuint) texture->getHandle();
|
||||
bindTextureToUnit(textype, handle, textureunit, restoreprev, bindforedit);
|
||||
}
|
||||
|
||||
@@ -1537,6 +1431,8 @@ bool OpenGL::isBufferUsageSupported(BufferUsage usage) const
|
||||
return true;
|
||||
case BUFFERUSAGE_TEXEL:
|
||||
return GLAD_VERSION_3_1 || GLAD_ES_VERSION_3_2;
|
||||
case BUFFERUSAGE_UNIFORM:
|
||||
return GLAD_VERSION_3_1 || GLAD_ES_VERSION_3_0;
|
||||
case BUFFERUSAGE_SHADER_STORAGE:
|
||||
return (GLAD_VERSION_4_3 && isCoreProfile()) || GLAD_ES_VERSION_3_1;
|
||||
case BUFFERUSAGE_INDIRECT_ARGUMENTS:
|
||||
|
||||
@@ -330,11 +330,6 @@ public:
|
||||
**/
|
||||
GLuint getDefaultFBO() const;
|
||||
|
||||
/**
|
||||
* Gets the ID for love's default texture (used for "untextured" primitives.)
|
||||
**/
|
||||
GLuint getDefaultTexture(TextureType type, DataBaseType datatype) const;
|
||||
|
||||
/**
|
||||
* Gets the texture ID for love's default texel buffer.
|
||||
**/
|
||||
@@ -492,7 +487,6 @@ private:
|
||||
void initVendor();
|
||||
void initOpenGLFunctions();
|
||||
void initMaxValues();
|
||||
void createDefaultTexture();
|
||||
|
||||
bool contextInitialized;
|
||||
|
||||
@@ -550,7 +544,6 @@ private:
|
||||
|
||||
GLuint boundFramebuffers[2];
|
||||
|
||||
GLuint defaultTexture[TEXTURE_MAX_ENUM][DATA_BASETYPE_MAX_ENUM];
|
||||
GLuint defaultTexelBuffer;
|
||||
GLuint defaultStorageBuffer;
|
||||
|
||||
|
||||
@@ -110,6 +110,8 @@ void Shader::mapActiveUniforms()
|
||||
std::map<std::string, UniformInfo> olduniforms = uniforms;
|
||||
uniforms.clear();
|
||||
|
||||
auto gfx = Module::getInstance<love::graphics::Graphics>(Module::M_GRAPHICS);
|
||||
|
||||
for (int uindex = 0; uindex < numuniforms; uindex++)
|
||||
{
|
||||
GLsizei namelen = 0;
|
||||
@@ -140,7 +142,7 @@ void Shader::mapActiveUniforms()
|
||||
continue;
|
||||
|
||||
if (!fillUniformReflectionData(u))
|
||||
continue;;
|
||||
continue;
|
||||
|
||||
if ((u.baseType == UNIFORM_SAMPLER && builtin != BUILTIN_TEXTURE_MAIN) || u.baseType == UNIFORM_TEXELBUFFER)
|
||||
{
|
||||
@@ -156,7 +158,7 @@ void Shader::mapActiveUniforms()
|
||||
else
|
||||
{
|
||||
unit.isTexelBuffer = false;
|
||||
unit.texture = gl.getDefaultTexture(u.textureType, u.dataBaseType);
|
||||
unit.texture = 0; // Handled below.
|
||||
}
|
||||
|
||||
for (int i = 0; i < u.count; i++)
|
||||
@@ -165,7 +167,7 @@ void Shader::mapActiveUniforms()
|
||||
else if (u.baseType == UNIFORM_STORAGETEXTURE)
|
||||
{
|
||||
StorageTextureBinding binding = {};
|
||||
binding.gltexture = gl.getDefaultTexture(u.textureType, u.dataBaseType);
|
||||
binding.gltexture = 0; // Handled below.
|
||||
binding.type = u.textureType;
|
||||
|
||||
if ((u.access & (ACCESS_READ | ACCESS_WRITE)) != 0)
|
||||
@@ -247,7 +249,13 @@ void Shader::mapActiveUniforms()
|
||||
else
|
||||
{
|
||||
u.textures = new love::graphics::Texture*[u.count];
|
||||
memset(u.textures, 0, sizeof(Texture *) * u.count);
|
||||
|
||||
auto *tex = gfx->getDefaultTexture(u.textureType, u.dataBaseType);
|
||||
for (int i = 0; i < u.count; i++)
|
||||
{
|
||||
tex->retain();
|
||||
u.textures[i] = tex;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (u.baseType == UNIFORM_STORAGETEXTURE)
|
||||
@@ -259,7 +267,20 @@ void Shader::mapActiveUniforms()
|
||||
glUniform1iv(u.location, u.count, u.ints);
|
||||
|
||||
u.textures = new love::graphics::Texture*[u.count];
|
||||
memset(u.textures, 0, sizeof(Texture *) * u.count);
|
||||
|
||||
if ((u.access & ACCESS_WRITE) != 0)
|
||||
{
|
||||
memset(u.textures, 0, sizeof(Texture *) * u.count);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto *tex = gfx->getDefaultTexture(u.textureType, u.dataBaseType);
|
||||
for (int i = 0; i < u.count; i++)
|
||||
{
|
||||
tex->retain();
|
||||
u.textures[i] = tex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,8 +798,14 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
|
||||
{
|
||||
if (!validateTexture(info, tex, internalUpdate))
|
||||
continue;
|
||||
tex->retain();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto gfx = Module::getInstance<love::graphics::Graphics>(Module::M_GRAPHICS);
|
||||
tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType);
|
||||
}
|
||||
|
||||
tex->retain();
|
||||
|
||||
if (info->textures[i] != nullptr)
|
||||
info->textures[i]->release();
|
||||
@@ -787,11 +814,7 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
|
||||
|
||||
if (isstoragetex)
|
||||
{
|
||||
GLuint gltex = 0;
|
||||
if (tex != nullptr)
|
||||
gltex = (GLuint) tex->getHandle();
|
||||
else
|
||||
gltex = gl.getDefaultTexture(info->textureType, info->dataBaseType);
|
||||
GLuint gltex = (GLuint) tex->getHandle();
|
||||
|
||||
int bindingindex = info->ints[i];
|
||||
auto &binding = storageTextureBindings[bindingindex];
|
||||
@@ -804,11 +827,7 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
|
||||
}
|
||||
else
|
||||
{
|
||||
GLuint gltex = 0;
|
||||
if (textures[i] != nullptr)
|
||||
gltex = (GLuint) tex->getHandle();
|
||||
else
|
||||
gltex = gl.getDefaultTexture(info->textureType, info->dataBaseType);
|
||||
GLuint gltex = (GLuint) tex->getHandle();
|
||||
|
||||
int texunit = info->ints[i];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user