Merge branch '12.0-development' into metal

This commit is contained in:
Alex Szpakowski
2020-07-29 18:21:19 -03:00
57 changed files with 6870 additions and 4915 deletions
+208 -19
View File
@@ -24,6 +24,7 @@
#include "Shader.h"
#include "ShaderStage.h"
#include "Graphics.h"
#include "graphics/vertex.h"
// C++
#include <algorithm>
@@ -68,6 +69,16 @@ Shader::~Shader()
delete[] p.second.textures;
}
else if (p.second.baseType == UNIFORM_TEXELBUFFER)
{
for (int i = 0; i < p.second.count; i++)
{
if (p.second.buffers[i] != nullptr)
p.second.buffers[i]->release();
}
delete[] p.second.buffers;
}
}
}
@@ -106,6 +117,7 @@ void Shader::mapActiveUniforms()
u.location = glGetUniformLocation(program, u.name.c_str());
u.baseType = getUniformBaseType(gltype);
u.textureType = getUniformTextureType(gltype);
u.texelBufferType = getUniformTexelBufferType(gltype);
u.isDepthSampler = isDepthTextureType(gltype);
if (u.baseType == UNIFORM_MATRIX)
@@ -129,12 +141,22 @@ void Shader::mapActiveUniforms()
if (u.location == -1)
continue;
if (u.baseType == UNIFORM_SAMPLER && builtin != BUILTIN_TEXTURE_MAIN)
if ((u.baseType == UNIFORM_SAMPLER && builtin != BUILTIN_TEXTURE_MAIN) || u.baseType == UNIFORM_TEXELBUFFER)
{
TextureUnit unit;
unit.type = u.textureType;
unit.active = true;
unit.texture = gl.getDefaultTexture(u.textureType);
if (u.baseType == UNIFORM_TEXELBUFFER)
{
unit.isTexelBuffer = true;
unit.texture = gl.getDefaultTexelBuffer();
}
else
{
unit.isTexelBuffer = false;
unit.texture = gl.getDefaultTexture(u.textureType);
}
for (int i = 0; i < u.count; i++)
textureUnits.push_back(unit);
@@ -164,6 +186,7 @@ void Shader::mapActiveUniforms()
case UNIFORM_INT:
case UNIFORM_BOOL:
case UNIFORM_SAMPLER:
case UNIFORM_TEXELBUFFER:
u.dataSize = sizeof(int) * u.components * u.count;
u.data = malloc(u.dataSize);
break;
@@ -183,7 +206,7 @@ void Shader::mapActiveUniforms()
{
memset(u.data, 0, u.dataSize);
if (u.baseType == UNIFORM_SAMPLER)
if (u.baseType == UNIFORM_SAMPLER || u.baseType == UNIFORM_TEXELBUFFER)
{
int startunit = (int) textureUnits.size() - u.count;
@@ -195,8 +218,16 @@ 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.baseType == UNIFORM_TEXELBUFFER)
{
u.buffers = new love::graphics::Buffer*[u.count];
memset(u.buffers, 0, sizeof(Buffer *) * u.count);
}
else
{
u.textures = new love::graphics::Texture*[u.count];
memset(u.textures, 0, sizeof(Texture *) * u.count);
}
}
}
@@ -257,7 +288,6 @@ void Shader::mapActiveUniforms()
{
if (u.textures[i] == nullptr)
continue;
Volatile *v = dynamic_cast<Volatile *>(u.textures[i]);
if (v != nullptr)
v->loadVolatile();
@@ -265,6 +295,19 @@ void Shader::mapActiveUniforms()
sendTextures(&u, u.textures, u.count, true);
}
else if (u.baseType == UNIFORM_TEXELBUFFER)
{
for (int i = 0; i < u.count; i++)
{
if (u.buffers[i] == nullptr)
continue;
Volatile *v = dynamic_cast<Volatile *>(u.buffers[i]);
if (v != nullptr)
v->loadVolatile();
}
sendBuffers(&u, u.buffers, u.count, true);
}
}
// Make sure uniforms that existed before but don't exist anymore are
@@ -275,16 +318,26 @@ void Shader::mapActiveUniforms()
{
free(p.second.data);
if (p.second.baseType != UNIFORM_SAMPLER)
continue;
for (int i = 0; i < p.second.count; i++)
if (p.second.baseType == UNIFORM_SAMPLER)
{
if (p.second.textures[i] != nullptr)
p.second.textures[i]->release();
}
for (int i = 0; i < p.second.count; i++)
{
if (p.second.textures[i] != nullptr)
p.second.textures[i]->release();
}
delete[] p.second.textures;
delete[] p.second.textures;
}
else if (p.second.baseType == UNIFORM_TEXELBUFFER)
{
for (int i = 0; i < p.second.count; i++)
{
if (p.second.buffers[i] != nullptr)
p.second.buffers[i]->release();
}
delete[] p.second.buffers;
}
}
}
@@ -322,7 +375,7 @@ bool Shader::loadVolatile()
for (int i = 0; i < int(ATTRIB_MAX_ENUM); i++)
{
const char *name = nullptr;
if (vertex::getConstant((BuiltinVertexAttribute) i, name))
if (graphics::getConstant((BuiltinVertexAttribute) i, name))
glBindAttribLocation(program, i, (const GLchar *) name);
}
@@ -430,7 +483,12 @@ void Shader::attach()
{
const TextureUnit &unit = textureUnits[i];
if (unit.active)
gl.bindTextureToUnit(unit.type, unit.texture, i, false);
{
if (unit.isTexelBuffer)
gl.bindBufferTextureToUnit(unit.texture, i, false, false);
else
gl.bindTextureToUnit(unit.type, unit.texture, i, false, false);
}
}
// send any pending uniforms to the shader program.
@@ -493,7 +551,7 @@ void Shader::updateUniform(const UniformInfo *info, int count, bool internalupda
break;
}
}
else if (type == UNIFORM_INT || type == UNIFORM_BOOL || type == UNIFORM_SAMPLER)
else if (type == UNIFORM_INT || type == UNIFORM_BOOL || type == UNIFORM_SAMPLER || type == UNIFORM_TEXELBUFFER)
{
switch (info->components)
{
@@ -627,7 +685,110 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
int texunit = info->ints[i];
if (shaderactive)
gl.bindTextureToUnit(info->textureType, gltex, texunit, false);
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)
{
Shader::sendBuffers(info, buffers, count, false);
}
static bool isTexelBufferTypeCompatible(DataBaseType a, DataBaseType b)
{
if (a == DATA_BASETYPE_FLOAT || a == DATA_BASETYPE_UNORM || a == DATA_BASETYPE_SNORM)
return b == DATA_BASETYPE_FLOAT || b == DATA_BASETYPE_UNORM || b == DATA_BASETYPE_SNORM;
if (a == DATA_BASETYPE_INT && b == DATA_BASETYPE_INT)
return true;
if (a == DATA_BASETYPE_UINT && b == DATA_BASETYPE_UINT)
return true;
return false;
}
void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count, bool internalUpdate)
{
if (info->baseType != UNIFORM_TEXELBUFFER)
return;
uint32 requiredtypeflags = Buffer::TYPEFLAG_TEXEL;
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++)
{
love::graphics::Buffer *buffer = buffers[i];
if (buffer != nullptr)
{
if ((buffer->getTypeFlags() & requiredtypeflags) == 0)
{
if (internalUpdate)
continue;
else
throw love::Exception("Shader uniform '%s' is a texel buffer, but the given Buffer was not created with texel buffer capabilities.", info->name.c_str());
}
DataBaseType basetype = buffer->getDataMember(0).info.baseType;
if (!isTexelBufferTypeCompatible(basetype, info->texelBufferType))
{
if (internalUpdate)
continue;
else
throw love::Exception("Texel buffer's data format base type must match the variable declared in the shader.");
}
buffer->retain();
}
bool addbuffertoarray = true;
if (info->buffers[i] != nullptr)
{
Buffer *oldbuffer = info->buffers[i];
auto it = std::find(buffersToUnmap.begin(), buffersToUnmap.end(), oldbuffer);
if (it != buffersToUnmap.end())
{
addbuffertoarray = false;
if (buffer != nullptr)
*it = buffer;
else
{
auto last = buffersToUnmap.end() - 1;
*it = *last;
buffersToUnmap.erase(last);
}
}
oldbuffer->release();
}
if (addbuffertoarray && buffer != nullptr)
buffersToUnmap.push_back(buffer);
info->buffers[i] = buffer;
GLuint gltex = 0;
if (buffers[i] != nullptr)
gltex = (GLuint) buffer->getTexelBufferHandle();
else
gltex = gl.getDefaultTexelBuffer();
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;
@@ -746,11 +907,20 @@ void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW,
GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW];
if (location >= 0)
glUniform4fv(location, 13, (const GLfloat *) &data);
// TODO: Find a better place to put this.
// Buffers used in this shader can be mapped by external code without
// unmapping. We need to make sure the data on the GPU is up to date,
// otherwise the shader can read from old data.
for (Buffer *buffer : buffersToUnmap)
buffer->unmap();
}
int Shader::getUniformTypeComponents(GLenum type) const
{
if (getUniformBaseType(type) == UNIFORM_SAMPLER)
UniformType basetype = getUniformBaseType(type);
if (basetype == UNIFORM_SAMPLER || basetype == UNIFORM_TEXELBUFFER)
return 1;
switch (type)
@@ -879,6 +1049,10 @@ Shader::UniformType Shader::getUniformBaseType(GLenum type) const
case GL_SAMPLER_CUBE_MAP_ARRAY:
case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
return UNIFORM_SAMPLER;
case GL_SAMPLER_BUFFER:
case GL_INT_SAMPLER_BUFFER:
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
return UNIFORM_TEXELBUFFER;
default:
return UNIFORM_UNKNOWN;
}
@@ -922,6 +1096,21 @@ TextureType Shader::getUniformTextureType(GLenum type) const
}
}
DataBaseType Shader::getUniformTexelBufferType(GLenum type) const
{
switch (type)
{
case GL_SAMPLER_BUFFER:
return DATA_BASETYPE_FLOAT;
case GL_INT_SAMPLER_BUFFER:
return DATA_BASETYPE_INT;
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
return DATA_BASETYPE_UINT;
default:
return DATA_BASETYPE_MAX_ENUM;
}
}
bool Shader::isDepthTextureType(GLenum type) const
{
switch (type)