Adding the ubo slot assignment for the resource texture table

This commit is contained in:
samcake 2017-01-26 11:04:46 -08:00 committed by Bradley Austin Davis
parent 536ada3973
commit 03aeb7adda
8 changed files with 573 additions and 35 deletions

View file

@ -98,6 +98,12 @@ public:
static const int MAX_NUM_RESOURCE_TEXTURES = 16;
size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; }
// Texture Tables offers 2 dedicated slot (taken from the ubo slots)
static const int MAX_NUM_RESOURCE_TABLE_TEXTURES = 2;
static const int RESOURCE_TABLE_TEXTURE_SLOT_OFFSET = TRANSFORM_CAMERA_SLOT + 1;
size_t getMaxNumResourceTextureTables() const { return MAX_NUM_RESOURCE_TABLE_TEXTURES; }
// Draw Stage
virtual void do_draw(const Batch& batch, size_t paramOffset) = 0;
virtual void do_drawIndexed(const Batch& batch, size_t paramOffset) = 0;

View file

@ -10,6 +10,447 @@
#include "GLBackend.h"
namespace gpu {
namespace gl {
class ElementResource {
public:
gpu::Element _element;
uint16 _resource;
ElementResource(Element&& elem, uint16 resource) : _element(elem), _resource(resource) {}
};
ElementResource getFormatFromGLUniform(GLenum gltype) {
switch (gltype) {
case GL_FLOAT: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
case GL_FLOAT_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
case GL_FLOAT_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
case GL_FLOAT_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
/*
case GL_DOUBLE: return ElementResource(Element(SCALAR, gpu::FLOAT, UNIFORM), Resource::BUFFER);
case GL_DOUBLE_VEC2: return ElementResource(Element(VEC2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
case GL_DOUBLE_VEC3: return ElementResource(Element(VEC3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
case GL_DOUBLE_VEC4: return ElementResource(Element(VEC4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
*/
case GL_INT: return ElementResource(Element(SCALAR, gpu::INT32, UNIFORM), Resource::BUFFER);
case GL_INT_VEC2: return ElementResource(Element(VEC2, gpu::INT32, UNIFORM), Resource::BUFFER);
case GL_INT_VEC3: return ElementResource(Element(VEC3, gpu::INT32, UNIFORM), Resource::BUFFER);
case GL_INT_VEC4: return ElementResource(Element(VEC4, gpu::INT32, UNIFORM), Resource::BUFFER);
case GL_UNSIGNED_INT: return ElementResource(Element(SCALAR, gpu::UINT32, UNIFORM), Resource::BUFFER);
#if defined(Q_OS_WIN)
case GL_UNSIGNED_INT_VEC2: return ElementResource(Element(VEC2, gpu::UINT32, UNIFORM), Resource::BUFFER);
case GL_UNSIGNED_INT_VEC3: return ElementResource(Element(VEC3, gpu::UINT32, UNIFORM), Resource::BUFFER);
case GL_UNSIGNED_INT_VEC4: return ElementResource(Element(VEC4, gpu::UINT32, UNIFORM), Resource::BUFFER);
#endif
case GL_BOOL: return ElementResource(Element(SCALAR, gpu::BOOL, UNIFORM), Resource::BUFFER);
case GL_BOOL_VEC2: return ElementResource(Element(VEC2, gpu::BOOL, UNIFORM), Resource::BUFFER);
case GL_BOOL_VEC3: return ElementResource(Element(VEC3, gpu::BOOL, UNIFORM), Resource::BUFFER);
case GL_BOOL_VEC4: return ElementResource(Element(VEC4, gpu::BOOL, UNIFORM), Resource::BUFFER);
case GL_FLOAT_MAT2: return ElementResource(Element(gpu::MAT2, gpu::FLOAT, UNIFORM), Resource::BUFFER);
case GL_FLOAT_MAT3: return ElementResource(Element(MAT3, gpu::FLOAT, UNIFORM), Resource::BUFFER);
case GL_FLOAT_MAT4: return ElementResource(Element(MAT4, gpu::FLOAT, UNIFORM), Resource::BUFFER);
/* {GL_FLOAT_MAT2x3 mat2x3},
{GL_FLOAT_MAT2x4 mat2x4},
{GL_FLOAT_MAT3x2 mat3x2},
{GL_FLOAT_MAT3x4 mat3x4},
{GL_FLOAT_MAT4x2 mat4x2},
{GL_FLOAT_MAT4x3 mat4x3},
{GL_DOUBLE_MAT2 dmat2},
{GL_DOUBLE_MAT3 dmat3},
{GL_DOUBLE_MAT4 dmat4},
{GL_DOUBLE_MAT2x3 dmat2x3},
{GL_DOUBLE_MAT2x4 dmat2x4},
{GL_DOUBLE_MAT3x2 dmat3x2},
{GL_DOUBLE_MAT3x4 dmat3x4},
{GL_DOUBLE_MAT4x2 dmat4x2},
{GL_DOUBLE_MAT4x3 dmat4x3},
*/
case GL_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D);
case GL_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D);
case GL_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_3D);
case GL_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_CUBE);
#if defined(Q_OS_WIN)
case GL_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
case GL_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_1D_ARRAY);
case GL_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER), Resource::TEXTURE_2D_ARRAY);
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
#endif
case GL_SAMPLER_2D_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D);
#if defined(Q_OS_WIN)
case GL_SAMPLER_CUBE_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_CUBE);
case GL_SAMPLER_2D_ARRAY_SHADOW: return ElementResource(Element(SCALAR, gpu::FLOAT, SAMPLER_SHADOW), Resource::TEXTURE_2D_ARRAY);
#endif
// {GL_SAMPLER_1D_SHADOW sampler1DShadow},
// {GL_SAMPLER_1D_ARRAY_SHADOW sampler1DArrayShadow},
// {GL_SAMPLER_BUFFER samplerBuffer},
// {GL_SAMPLER_2D_RECT sampler2DRect},
// {GL_SAMPLER_2D_RECT_SHADOW sampler2DRectShadow},
#if defined(Q_OS_WIN)
case GL_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D);
case GL_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D);
case GL_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
case GL_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_3D);
case GL_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_CUBE);
case GL_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
case GL_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::INT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
// {GL_INT_SAMPLER_BUFFER isamplerBuffer},
// {GL_INT_SAMPLER_2D_RECT isampler2DRect},
case GL_UNSIGNED_INT_SAMPLER_1D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D);
case GL_UNSIGNED_INT_SAMPLER_2D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D);
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D);
case GL_UNSIGNED_INT_SAMPLER_3D: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_3D);
case GL_UNSIGNED_INT_SAMPLER_CUBE: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_CUBE);
case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_1D_ARRAY);
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER), Resource::TEXTURE_2D_ARRAY);
case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return ElementResource(Element(SCALAR, gpu::UINT32, SAMPLER_MULTISAMPLE), Resource::TEXTURE_2D_ARRAY);
#endif
// {GL_UNSIGNED_INT_SAMPLER_BUFFER usamplerBuffer},
// {GL_UNSIGNED_INT_SAMPLER_2D_RECT usampler2DRect},
/*
{GL_IMAGE_1D image1D},
{GL_IMAGE_2D image2D},
{GL_IMAGE_3D image3D},
{GL_IMAGE_2D_RECT image2DRect},
{GL_IMAGE_CUBE imageCube},
{GL_IMAGE_BUFFER imageBuffer},
{GL_IMAGE_1D_ARRAY image1DArray},
{GL_IMAGE_2D_ARRAY image2DArray},
{GL_IMAGE_2D_MULTISAMPLE image2DMS},
{GL_IMAGE_2D_MULTISAMPLE_ARRAY image2DMSArray},
{GL_INT_IMAGE_1D iimage1D},
{GL_INT_IMAGE_2D iimage2D},
{GL_INT_IMAGE_3D iimage3D},
{GL_INT_IMAGE_2D_RECT iimage2DRect},
{GL_INT_IMAGE_CUBE iimageCube},
{GL_INT_IMAGE_BUFFER iimageBuffer},
{GL_INT_IMAGE_1D_ARRAY iimage1DArray},
{GL_INT_IMAGE_2D_ARRAY iimage2DArray},
{GL_INT_IMAGE_2D_MULTISAMPLE iimage2DMS},
{GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY iimage2DMSArray},
{GL_UNSIGNED_INT_IMAGE_1D uimage1D},
{GL_UNSIGNED_INT_IMAGE_2D uimage2D},
{GL_UNSIGNED_INT_IMAGE_3D uimage3D},
{GL_UNSIGNED_INT_IMAGE_2D_RECT uimage2DRect},
{GL_UNSIGNED_INT_IMAGE_CUBE uimageCube},+ [0] {_name="fInnerRadius" _location=0 _element={_semantic=15 '\xf' _dimension=0 '\0' _type=0 '\0' } } gpu::Shader::Slot
{GL_UNSIGNED_INT_IMAGE_BUFFER uimageBuffer},
{GL_UNSIGNED_INT_IMAGE_1D_ARRAY uimage1DArray},
{GL_UNSIGNED_INT_IMAGE_2D_ARRAY uimage2DArray},
{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE uimage2DMS},
{GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY uimage2DMSArray},
{GL_UNSIGNED_INT_ATOMIC_COUNTER atomic_uint}
*/
default:
return ElementResource(Element(), Resource::BUFFER);
}
};
int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& textureTables, Shader::SlotSet& samplers) {
GLint uniformsCount = 0;
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount);
for (int i = 0; i < uniformsCount; i++) {
const GLint NAME_LENGTH = 256;
GLchar name[NAME_LENGTH];
GLint length = 0;
GLint size = 0;
GLenum type = 0;
glGetActiveUniform(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
GLint location = glGetUniformLocation(glprogram, name);
const GLint INVALID_UNIFORM_LOCATION = -1;
// Try to make sense of the gltype
auto elementResource = getFormatFromGLUniform(type);
// The uniform as a standard var type
if (location != INVALID_UNIFORM_LOCATION) {
// Let's make sure the name doesn't contains an array element
std::string sname(name);
auto foundBracket = sname.find_first_of('[');
if (foundBracket != std::string::npos) {
// std::string arrayname = sname.substr(0, foundBracket);
if (sname[foundBracket + 1] == '0') {
sname = sname.substr(0, foundBracket);
} else {
// skip this uniform since it's not the first element of an array
continue;
}
}
if (elementResource._resource == Resource::BUFFER) {
uniforms.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource));
} else {
// For texture/Sampler, the location is the actual binding value
GLint binding = -1;
glGetUniformiv(glprogram, location, &binding);
auto requestedBinding = slotBindings.find(std::string(sname));
if (requestedBinding != slotBindings.end()) {
if (binding != (*requestedBinding)._location) {
binding = (*requestedBinding)._location;
glProgramUniform1i(glprogram, location, binding);
}
}
textures.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
samplers.insert(Shader::Slot(name, binding, elementResource._element, elementResource._resource));
}
}
}
return uniformsCount;
}
const GLint UNUSED_SLOT = -1;
bool isUnusedSlot(GLint binding) {
return (binding == UNUSED_SLOT);
}
int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) {
GLint buffersCount = 0;
glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount);
// fast exit
if (buffersCount == 0) {
return 0;
}
GLint maxNumUniformBufferSlots = 0;
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxNumUniformBufferSlots);
std::vector<GLint> uniformBufferSlotMap(maxNumUniformBufferSlots, -1);
struct UniformBlockInfo {
using Vector = std::vector<UniformBlockInfo>;
const GLuint index { 0 };
const std::string name;
GLint binding { -1 };
GLint size { 0 };
static std::string getName(GLuint glprogram, GLuint i) {
static const GLint NAME_LENGTH = 256;
GLint length = 0;
GLchar nameBuffer[NAME_LENGTH];
glGetActiveUniformBlockiv(glprogram, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &length);
glGetActiveUniformBlockName(glprogram, i, NAME_LENGTH, &length, nameBuffer);
return std::string(nameBuffer);
}
UniformBlockInfo(GLuint glprogram, GLuint i) : index(i), name(getName(glprogram, i)) {
glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_BINDING, &binding);
glGetActiveUniformBlockiv(glprogram, index, GL_UNIFORM_BLOCK_DATA_SIZE, &size);
}
};
UniformBlockInfo::Vector uniformBlocks;
uniformBlocks.reserve(buffersCount);
for (int i = 0; i < buffersCount; i++) {
uniformBlocks.push_back(UniformBlockInfo(glprogram, i));
}
for (auto& info : uniformBlocks) {
auto requestedBinding = slotBindings.find(info.name);
if (requestedBinding != slotBindings.end()) {
info.binding = (*requestedBinding)._location;
glUniformBlockBinding(glprogram, info.index, info.binding);
uniformBufferSlotMap[info.binding] = info.index;
}
}
for (auto& info : uniformBlocks) {
if (slotBindings.count(info.name)) {
continue;
}
// If the binding is 0, or the binding maps to an already used binding
if (info.binding == 0 || uniformBufferSlotMap[info.binding] != UNUSED_SLOT) {
// If no binding was assigned then just do it finding a free slot
auto slotIt = std::find_if(uniformBufferSlotMap.begin(), uniformBufferSlotMap.end(), isUnusedSlot);
if (slotIt != uniformBufferSlotMap.end()) {
info.binding = slotIt - uniformBufferSlotMap.begin();
glUniformBlockBinding(glprogram, info.index, info.binding);
} else {
// This should neve happen, an active ubo cannot find an available slot among the max available?!
info.binding = -1;
}
}
uniformBufferSlotMap[info.binding] = info.index;
}
for (auto& info : uniformBlocks) {
static const Element element(SCALAR, gpu::UINT32, gpu::UNIFORM_BUFFER);
buffers.insert(Shader::Slot(info.name, info.binding, element, Resource::BUFFER, info.size));
}
return buffersCount;
}
int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs) {
GLint inputsCount = 0;
glGetProgramiv(glprogram, GL_ACTIVE_ATTRIBUTES, &inputsCount);
for (int i = 0; i < inputsCount; i++) {
const GLint NAME_LENGTH = 256;
GLchar name[NAME_LENGTH];
GLint length = 0;
GLint size = 0;
GLenum type = 0;
glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
GLint binding = glGetAttribLocation(glprogram, name);
auto elementResource = getFormatFromGLUniform(type);
inputs.insert(Shader::Slot(name, binding, elementResource._element, -1));
}
return inputsCount;
}
int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs) {
/* GLint outputsCount = 0;
glGetProgramiv(glprogram, GL_ACTIVE_, &outputsCount);
for (int i = 0; i < inputsCount; i++) {
const GLint NAME_LENGTH = 256;
GLchar name[NAME_LENGTH];
GLint length = 0;
GLint size = 0;
GLenum type = 0;
glGetActiveAttrib(glprogram, i, NAME_LENGTH, &length, &size, &type, name);
auto element = getFormatFromGLUniform(type);
outputs.insert(Shader::Slot(name, i, element));
}
*/
return 0; //inputsCount;
}
void makeProgramBindings(ShaderObject& shaderObject) {
if (!shaderObject.glprogram) {
return;
}
GLuint glprogram = shaderObject.glprogram;
GLint loc = -1;
//Check for gpu specific attribute slotBindings
loc = glGetAttribLocation(glprogram, "inPosition");
if (loc >= 0 && loc != gpu::Stream::POSITION) {
glBindAttribLocation(glprogram, gpu::Stream::POSITION, "inPosition");
}
loc = glGetAttribLocation(glprogram, "inNormal");
if (loc >= 0 && loc != gpu::Stream::NORMAL) {
glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "inNormal");
}
loc = glGetAttribLocation(glprogram, "inColor");
if (loc >= 0 && loc != gpu::Stream::COLOR) {
glBindAttribLocation(glprogram, gpu::Stream::COLOR, "inColor");
}
loc = glGetAttribLocation(glprogram, "inTexCoord0");
if (loc >= 0 && loc != gpu::Stream::TEXCOORD) {
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD, "inTexCoord0");
}
loc = glGetAttribLocation(glprogram, "inTangent");
if (loc >= 0 && loc != gpu::Stream::TANGENT) {
glBindAttribLocation(glprogram, gpu::Stream::TANGENT, "inTangent");
}
loc = glGetAttribLocation(glprogram, "inTexCoord1");
if (loc >= 0 && loc != gpu::Stream::TEXCOORD1) {
glBindAttribLocation(glprogram, gpu::Stream::TEXCOORD1, "inTexCoord1");
}
loc = glGetAttribLocation(glprogram, "inSkinClusterIndex");
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_INDEX) {
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_INDEX, "inSkinClusterIndex");
}
loc = glGetAttribLocation(glprogram, "inSkinClusterWeight");
if (loc >= 0 && loc != gpu::Stream::SKIN_CLUSTER_WEIGHT) {
glBindAttribLocation(glprogram, gpu::Stream::SKIN_CLUSTER_WEIGHT, "inSkinClusterWeight");
}
loc = glGetAttribLocation(glprogram, "_drawCallInfo");
if (loc >= 0 && loc != gpu::Stream::DRAW_CALL_INFO) {
glBindAttribLocation(glprogram, gpu::Stream::DRAW_CALL_INFO, "_drawCallInfo");
}
// Link again to take into account the assigned attrib location
glLinkProgram(glprogram);
GLint linked = 0;
glGetProgramiv(glprogram, GL_LINK_STATUS, &linked);
if (!linked) {
qCWarning(gpugllogging) << "GLShader::makeBindings - failed to link after assigning slotBindings?";
}
// now assign the ubo binding, then DON't relink!
//Check for gpu specific uniform slotBindings
#ifdef GPU_SSBO_DRAW_CALL_INFO
loc = glGetProgramResourceIndex(glprogram, GL_SHADER_STORAGE_BLOCK, "transformObjectBuffer");
if (loc >= 0) {
glShaderStorageBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT);
shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT;
}
#else
loc = glGetUniformLocation(glprogram, "transformObjectBuffer");
if (loc >= 0) {
glProgramUniform1i(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT);
shaderObject.transformObjectSlot = gpu::TRANSFORM_OBJECT_SLOT;
}
#endif
loc = glGetUniformBlockIndex(glprogram, "transformCameraBuffer");
if (loc >= 0) {
glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_CAMERA_SLOT);
shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT;
}
loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable0");
if (loc >= 0) {
glUniformBlockBinding(glprogram, loc, GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET);
shaderObject.resourceTextureTableSlot0 = GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET;
}
loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable1");
if (loc >= 0) {
glUniformBlockBinding(glprogram, loc, GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET + 1);
shaderObject.resourceTextureTableSlot1 = GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET + 1;
}
(void)CHECK_GL_ERROR();
}
}
}
using namespace gpu;
using namespace gpu::gl;
@ -73,8 +514,9 @@ bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::Bin
Shader::SlotSet uniforms;
Shader::SlotSet textures;
Shader::SlotSet textureTables;
Shader::SlotSet samplers;
backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers);
backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, textureTables, samplers);
Shader::SlotSet resourceBuffers;
backend.makeResourceBufferSlots(shaderObject.glprogram, slotBindings, resourceBuffers);

View file

@ -17,8 +17,19 @@ struct ShaderObject {
GLuint glprogram { 0 };
GLint transformCameraSlot { -1 };
GLint transformObjectSlot { -1 };
GLint resourceTextureTableSlot0 { -1 };
GLint resourceTextureTableSlot1 { -1 };
};
int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings,
Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& textureTables, Shader::SlotSet& samplers);
int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers);
int makeInputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& inputs);
int makeOutputSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& outputs);
void makeProgramBindings(ShaderObject& shaderObject);
class GLShader : public GPUObject {
public:
static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr);

View file

@ -103,7 +103,7 @@ public:
friend class GL45Backend;
using PromoteLambda = std::function<void()>;
const uvec4& getHandle();
protected:
GL45VariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
~GL45VariableAllocationTexture();

View file

@ -212,6 +212,7 @@ void GL45Texture::syncSampler() const {
glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, sampler.getMinMip());
glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
(void)CHECK_GL_ERROR();
}
using GL45FixedAllocationTexture = GL45Backend::GL45FixedAllocationTexture;
@ -275,6 +276,10 @@ GL45StrictResourceTexture::GL45StrictResourceTexture(const std::weak_ptr<GLBacke
if (texture.isAutogenerateMips()) {
generateMips();
}
// Re-sync the sampler to force access to the new mip level
syncSampler();
updateSize();
}
GL45StrictResourceTexture::~GL45StrictResourceTexture() {
@ -282,3 +287,80 @@ GL45StrictResourceTexture::~GL45StrictResourceTexture() {
Backend::textureResidentGPUMemSize.update(size(), 0);
}
const uvec4& GL45Texture::getHandle() {
if (uvec4() == _handleAndBias) {
auto handle = glGetTextureHandleARB(_id);
glMakeTextureHandleResidentARB(handle);
memcpy(&_handleAndBias, &handle, sizeof(handle));
}
_handleAndBias.z = _minMip;
return _handleAndBias;
}
using GL45TextureTable = GL45Backend::GL45TextureTable;
GLuint GL45TextureTable::allocate() {
GLuint result;
glCreateBuffers(1, &result);
return result;
}
GL45TextureTable::GL45TextureTable(const std::weak_ptr<GLBackend>& backend, const TextureTable& textureTable, const HandlesArray& handles, bool handlesComplete)
: Parent(backend, textureTable, allocate()), _stamp(textureTable.getStamp()), _handles(handles), _complete(handlesComplete) {
Backend::setGPUObject(textureTable, this);
// FIXME include these in overall buffer storage reporting
glNamedBufferStorage(_id, sizeof(uvec4) * TextureTable::COUNT, &_handles[0], 0);
}
GL45TextureTable::~GL45TextureTable() {
if (_id) {
auto backend = _backend.lock();
if (backend) {
// FIXME include these in overall buffer storage reporting
backend->releaseBuffer(_id, 0);
}
}
}
GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureTablePointer) {
const auto& textureTable = *textureTablePointer;
// Find the target handles
auto textures = textureTable.getTextures();
bool handlesComplete = true;
GL45TextureTable::HandlesArray handles{};
for (size_t i = 0; i < textures.size(); ++i) {
auto texture = textures[i];
if (!texture) {
continue;
}
// FIXME what if we have a non-transferrable texture here?
auto gltexture = (GL45Texture*)syncGPUObject(texture, true);
if (!gltexture) {
handlesComplete = false;
continue;
}
auto handle = gltexture->getHandle();
memcpy(&handles[i], &handle, sizeof(handle));
}
// If the object hasn't been created, or the object definition is out of date, drop and re-create
GL45TextureTable* object = Backend::getGPUObject<GL45TextureTable>(textureTable);
if (!object || object->_stamp != textureTable.getStamp() || !object->_complete || handles != object->_handles) {
object = new GL45TextureTable(shared_from_this(), textureTable, handles, handlesComplete);
}
return object;
}
void GL45Backend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) {
auto textureTable = batch._textureTables.get(batch._params[paramOffset]._uint);
auto slot = batch._params[paramOffset + 1]._uint;
GL45TextureTable* glTextureTable = syncGPUObject(textureTable);
if (glTextureTable) {
glBindBufferBase(GL_UNIFORM_BUFFER, slot + GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET, glTextureTable->_id);
}
}

View file

@ -30,6 +30,11 @@ class QDebug;
namespace gpu {
enum ReservedSlot {
#ifdef GPU_SSBO_DRAW_CALL_INFO
TRANSFORM_OBJECT_SLOT = 14,
#else
TRANSFORM_OBJECT_SLOT = 31,
#endif
TRANSFORM_CAMERA_SLOT = 15,
};

View file

@ -14,12 +14,12 @@
#define GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES 8
struct GPUTextureTable {
uvec2 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES];
uvec4 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES];
};
#define TextureTable(index, name) layout (std140) uniform gpu_textureTableBuffer { GPUTextureTable name; }
#define TextureTable(index, name) layout (std140) uniform gpu_resourceTextureTable##index { GPUTextureTable name; }
#define tableTex(name, slot) sampler2D(name._textures[slot])
#define tableTex(name, slot) sampler2D(name._textures[slot].xy)
#else

View file

@ -145,6 +145,17 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
}
auto textureCache = DependencyManager::get<TextureCache>();
if (!_drawMaterialTextures) {
_drawMaterialTextures = std::make_shared<gpu::TextureTable>();
_drawMaterialTextures->setTexture(model::MaterialKey::ALBEDO_MAP, textureCache->getWhiteTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::ROUGHNESS_MAP, textureCache->getWhiteTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::NORMAL_MAP, textureCache->getBlueTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::OCCLUSION_MAP, textureCache->getWhiteTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::SCATTERING_MAP, textureCache->getWhiteTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture());
}
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, _drawMaterial->getSchemaBuffer());
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, _drawMaterial->getTexMapArrayBuffer());
@ -172,9 +183,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
if (materialKey.isAlbedoMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView());
} else {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::ALBEDO_MAP, itr->second->getTextureView());
}
}
@ -182,11 +191,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
if (materialKey.isRoughnessMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::ROUGHNESS_MAP, itr->second->getTextureView());
}
}
@ -194,11 +199,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
if (materialKey.isNormalMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::NORMAL_MAP, itr->second->getTextureView());
}
}
@ -206,11 +207,11 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
if (materialKey.isMetallicMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView());
_drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::METALLIC_MAP, textureCache->getBlackTexture());
}
}
@ -218,11 +219,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
if (materialKey.isOcclusionMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::OCCLUSION_MAP, itr->second->getTextureView());
}
}
@ -230,11 +227,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
if (materialKey.isScatteringMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::SCATTERING_MAP, itr->second->getTextureView());
}
}
@ -243,17 +236,16 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
_drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, itr->second->getTextureView());
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::LIGHTMAP_MAP, textureCache->getGrayTexture());
}
} else if (materialKey.isEmissiveMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
_drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, itr->second->getTextureView());
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
_drawMaterialTextures->setTexture(model::MaterialKey::EMISSIVE_MAP, textureCache->getBlackTexture());
}
}
}