Fix the uniform target for bindless

This commit is contained in:
Bradley Austin Davis 2018-02-08 14:05:21 -08:00 committed by Brad Davis
parent ab5355dbdd
commit b7d0260a17
10 changed files with 259 additions and 527 deletions

View file

@ -10,447 +10,6 @@
#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;
@ -516,7 +75,8 @@ bool GLShader::makeProgram(GLBackend& backend, Shader& shader, const Shader::Bin
Shader::SlotSet textures;
Shader::SlotSet textureTables;
Shader::SlotSet samplers;
backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, textureTables, samplers);
//backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, textureTables, samplers);
backend.makeUniformSlots(shaderObject.glprogram, slotBindings, uniforms, textures, samplers);
Shader::SlotSet resourceBuffers;
backend.makeResourceBufferSlots(shaderObject.glprogram, slotBindings, resourceBuffers);

View file

@ -17,19 +17,10 @@ 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

@ -167,7 +167,6 @@ void GL41Texture::syncSampler() const {
glTexParameteri(_target, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]);
glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, (uint16)sampler.getMipOffset());
glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
@ -206,9 +205,6 @@ void GL41FixedAllocationTexture::allocateStorage() const {
void GL41FixedAllocationTexture::syncSampler() const {
Parent::syncSampler();
const Sampler& sampler = _gpuObject.getSampler();
auto baseMip = std::max<uint16_t>(sampler.getMipOffset(), sampler.getMinMip());
glTexParameteri(_target, GL_TEXTURE_BASE_LEVEL, baseMip);
glTexParameterf(_target, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.0f : sampler.getMaxMip()));
}

View file

@ -19,6 +19,7 @@
#define INCREMENTAL_TRANSFER 0
#define GPU_SSBO_TRANSFORM_OBJECT 1
#define GPU_BINDLESS_TEXTURES 1
namespace gpu { namespace gl45 {
@ -49,21 +50,6 @@ public:
static const std::string GL45_VERSION;
const std::string& getVersion() const override { return GL45_VERSION; }
class GL45TextureTable : public GLObject<TextureTable> {
static GLuint allocate();
using Parent = GLObject<TextureTable>;
public:
using HandlesArray = std::array<uvec4, TextureTable::COUNT>;
GL45TextureTable(const std::weak_ptr<GLBackend>& backend, const TextureTable& texture, const HandlesArray& newHandles, bool complete);
~GL45TextureTable();
// FIXME instead of making a buffer for each table, there should be a global buffer of all materials
// and we should store an offset into that buffer
const uint32_t _stamp { 0 };
const HandlesArray _handles;
const bool _complete { false };
};
class GL45Texture : public GLTexture {
using Parent = GLTexture;
friend class GL45Backend;
@ -73,8 +59,72 @@ public:
void generateMips() const override;
Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override;
void syncSampler() const override;
bool isBindless() const {
#if GPU_BINDLESS_TEXTURES
return _bindless.operator bool();
#else
return false;
#endif
}
#if GPU_BINDLESS_TEXTURES
struct Bindless {
uint64_t handle{ 0 };
uint32_t minMip{ 0 };
uint32_t sampler{ 0 };
operator bool() const {
return handle != 0;
}
};
virtual const Bindless& getBindless() const;
void releaseBindless() const;
void recreateBindless() const;
virtual uint16 getMinMip() const = 0;
private:
class InvalidSampler : public Sampler {
public:
InvalidSampler() {
_desc._borderColor = vec4(-1.0f);
}
operator const Sampler&() const {
return *this;
}
};
static const Sampler INVALID_SAMPLER;
// This stores the texture handle (64 bits) in xy, the min mip available in z, and the sampler ID in w
mutable Sampler _cachedSampler{ INVALID_SAMPLER };
mutable Bindless _bindless;
#endif
};
#if GPU_BINDLESS_TEXTURES
class GL45TextureTable : public GLObject<TextureTable> {
static GLuint allocate();
using Parent = GLObject<TextureTable>;
public:
using BindlessArray = std::array<GL45Texture::Bindless, TextureTable::COUNT>;
GL45TextureTable(const std::weak_ptr<GLBackend>& backend, const TextureTable& texture);
~GL45TextureTable();
void update(const BindlessArray& newHandles);
// FIXME instead of making a buffer for each table, there should be a global buffer of all materials
// and we should store an offset into that buffer
BindlessArray _handles;
};
#endif
//
// Textures that have fixed allocation sizes and cannot be managed at runtime
//
@ -89,6 +139,8 @@ public:
protected:
Size size() const override { return _size; }
uint16 getMinMip() const override { return 0; }
void allocateStorage() const;
void syncSampler() const override;
const Size _size { 0 };
@ -125,6 +177,8 @@ public:
~GL45VariableAllocationTexture();
Size size() const override { return _size; }
uint16 getMinMip() const override { return _populatedMip; }
virtual const Bindless& getBindless() const override;
Size copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const override;
void copyTextureMipsInGPUMem(GLuint srcId, GLuint destId, uint16_t srcMipOffset, uint16_t destMipOffset, uint16_t populatedMips) override;

View file

@ -165,6 +165,11 @@ void GL45Backend::makeProgramBindings(ShaderObject& shaderObject) {
shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT;
}
loc = glGetUniformBlockIndex(glprogram, "gpu_resourceTextureTable0");
if (loc >= 0) {
glUniformBlockBinding(glprogram, loc, RESOURCE_TABLE_TEXTURE_SLOT_OFFSET);
}
(void)CHECK_GL_ERROR();
}

View file

@ -20,6 +20,7 @@
#include <QtCore/QDebug>
#include <NumericalConstants.h>
#include <gl/Context.h>
#include <gpu/TextureTable.h>
#include "../gl/GLTexelFormat.h"
@ -29,6 +30,10 @@ using namespace gpu::gl45;
#define MAX_RESOURCE_TEXTURES_PER_FRAME 2
#pragma optimize("", off)
#define FORCE_STRICT_TEXTURE 0
#define ENABLE_SPARSE_TEXTURE 0
GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) {
if (!texturePointer) {
@ -52,14 +57,18 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) {
object = new GL45AttachmentTexture(shared_from_this(), texture);
break;
#if FORCE_STRICT_TEXTURE
case TextureUsageType::RESOURCE:
#endif
case TextureUsageType::STRICT_RESOURCE:
qCDebug(gpugllogging) << "Strict texture " << texture.source().c_str();
object = new GL45StrictResourceTexture(shared_from_this(), texture);
break;
#if !FORCE_STRICT_TEXTURE
case TextureUsageType::RESOURCE: {
if (GL45VariableAllocationTexture::_frameTexturesCreated < MAX_RESOURCE_TEXTURES_PER_FRAME) {
#if 0
#if ENABLE_SPARSE_TEXTURE
if (isTextureManagementSparseEnabled() && GL45Texture::isSparseEligible(texture)) {
object = new GL45SparseResourceTexture(shared_from_this(), texture);
} else {
@ -77,7 +86,7 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) {
}
break;
}
#endif
default:
Q_UNREACHABLE();
}
@ -115,6 +124,50 @@ void GL45Backend::initTextureManagementStage() {
using GL45Texture = GL45Backend::GL45Texture;
class GLSamplerCache {
public:
GLuint getGLSampler(const Sampler& sampler) {
if (0 == _samplerCache.count(sampler)) {
GLuint result = 0;
glGenSamplers(1, &result);
const auto& fm = GLTexture::FILTER_MODES[sampler.getFilter()];
glSamplerParameteri(result, GL_TEXTURE_MIN_FILTER, fm.minFilter);
glSamplerParameteri(result, GL_TEXTURE_MAG_FILTER, fm.magFilter);
if (sampler.doComparison()) {
glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB);
glSamplerParameteri(result, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]);
} else {
glSamplerParameteri(result, GL_TEXTURE_COMPARE_MODE, GL_NONE);
}
glSamplerParameteri(result, GL_TEXTURE_WRAP_S, GLTexture::WRAP_MODES[sampler.getWrapModeU()]);
glSamplerParameteri(result, GL_TEXTURE_WRAP_T, GLTexture::WRAP_MODES[sampler.getWrapModeV()]);
glSamplerParameteri(result, GL_TEXTURE_WRAP_R, GLTexture::WRAP_MODES[sampler.getWrapModeW()]);
glSamplerParameterf(result, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
glSamplerParameterfv(result, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
glSamplerParameterf(result, GL_TEXTURE_MIN_LOD, sampler.getMinMip());
glSamplerParameterf(result, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
_samplerCache[sampler] = result;
return result;
}
return _samplerCache[sampler];
}
void releaseGLSampler(GLuint sampler) {
// NO OP
}
private:
std::unordered_map<Sampler, GLuint> _samplerCache;
};
static GLSamplerCache SAMPLER_CACHE;
const Sampler GL45Texture::INVALID_SAMPLER = GL45Texture::InvalidSampler();
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture)
: GLTexture(backend, texture, allocate(texture)) {
}
@ -122,10 +175,10 @@ GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture&
GLuint GL45Texture::allocate(const Texture& texture) {
GLuint result;
glCreateTextures(getGLTextureType(texture), 1, &result);
#ifdef DEBUG
auto source = texture.source();
glObjectLabel(GL_TEXTURE, result, (GLsizei)source.length(), source.data());
#endif
if (::gl::Context::enableDebugLogger()) {
auto source = texture.source();
glObjectLabel(GL_TEXTURE, result, (GLsizei)source.length(), source.data());
}
return result;
}
@ -190,32 +243,69 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const
return amountCopied;
}
void GL45Texture::syncSampler() const {
const Sampler& sampler = _gpuObject.getSampler();
const auto& fm = FILTER_MODES[sampler.getFilter()];
glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter);
glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter);
if (sampler.doComparison()) {
glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB);
glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]);
} else {
glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE);
void GL45Texture::releaseBindless() const {
// Release the old handler
SAMPLER_CACHE.releaseGLSampler(_bindless.sampler);
glMakeTextureHandleNonResidentARB(_bindless.handle);
_bindless = Bindless();
}
void GL45Texture::recreateBindless() const {
if (isBindless()) {
releaseBindless();
}
glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]);
glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]);
glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]);
_bindless.sampler = SAMPLER_CACHE.getGLSampler(_cachedSampler);
_bindless.handle = glGetTextureSamplerHandleARB(_id, _bindless.sampler);
glMakeTextureHandleResidentARB(_bindless.handle);
}
glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
const GL45Texture::Bindless& GL45Texture::getBindless() const {
if (!_bindless) {
recreateBindless();
}
_bindless.minMip = getMinMip();
return _bindless;
}
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 GL45Texture::syncSampler() const {
const Sampler& sampler = _gpuObject.getSampler();
bool samplerChanged = _cachedSampler != sampler;
if (samplerChanged) {
_cachedSampler = sampler;
}
if (isBindless()) {
if (samplerChanged) {
recreateBindless();
}
} else if (samplerChanged) {
const auto& fm = FILTER_MODES[sampler.getFilter()];
glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter);
glTextureParameteri(_id, GL_TEXTURE_MAG_FILTER, fm.magFilter);
if (sampler.doComparison()) {
glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE_ARB);
glTextureParameteri(_id, GL_TEXTURE_COMPARE_FUNC, COMPARISON_TO_GL[sampler.getComparisonFunction()]);
} else {
glTextureParameteri(_id, GL_TEXTURE_COMPARE_MODE, GL_NONE);
}
glTextureParameteri(_id, GL_TEXTURE_WRAP_S, WRAP_MODES[sampler.getWrapModeU()]);
glTextureParameteri(_id, GL_TEXTURE_WRAP_T, WRAP_MODES[sampler.getWrapModeV()]);
glTextureParameteri(_id, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]);
glTextureParameterf(_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
glTextureParameterfv(_id, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor());
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();
}
// Fixed allocation textures, used for strict resources & framebuffer attachments
using GL45FixedAllocationTexture = GL45Backend::GL45FixedAllocationTexture;
GL45FixedAllocationTexture::GL45FixedAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45Texture(backend, texture), _size(texture.evalTotalSize()) {
@ -240,8 +330,6 @@ void GL45FixedAllocationTexture::allocateStorage() const {
void GL45FixedAllocationTexture::syncSampler() const {
Parent::syncSampler();
const Sampler& sampler = _gpuObject.getSampler();
auto baseMip = std::max<uint16_t>(sampler.getMipOffset(), sampler.getMinMip());
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, baseMip);
glTextureParameterf(_id, GL_TEXTURE_MIN_LOD, (float)sampler.getMinMip());
glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
}
@ -280,7 +368,6 @@ GL45StrictResourceTexture::GL45StrictResourceTexture(const std::weak_ptr<GLBacke
// Re-sync the sampler to force access to the new mip level
syncSampler();
updateSize();
}
GL45StrictResourceTexture::~GL45StrictResourceTexture() {
@ -288,16 +375,7 @@ 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;
}
// Encapsulate bindless textures
using GL45TextureTable = GL45Backend::GL45TextureTable;
GLuint GL45TextureTable::allocate() {
@ -306,13 +384,21 @@ GLuint GL45TextureTable::allocate() {
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) {
GL45TextureTable::GL45TextureTable(const std::weak_ptr<GLBackend>& backend, const TextureTable& textureTable)
: Parent(backend, textureTable, allocate()){
Backend::setGPUObject(textureTable, this);
// FIXME include these in overall buffer storage reporting
glNamedBufferStorage(_id, sizeof(uvec4) * TextureTable::COUNT, &_handles[0], 0);
glNamedBufferStorage(_id, sizeof(uvec4) * TextureTable::COUNT, nullptr, GL_DYNAMIC_STORAGE_BIT);
}
void GL45TextureTable::update(const BindlessArray& handles) {
if (_handles != handles) {
_handles = handles;
// FIXME include these in overall buffer storage reporting
// FIXME use a single shared buffer for bindless data
glNamedBufferSubData(_id, 0, sizeof(GL45Texture::Bindless) * TextureTable::COUNT, &_handles[0]);
}
}
GL45TextureTable::~GL45TextureTable() {
if (_id) {
@ -324,36 +410,33 @@ GL45TextureTable::~GL45TextureTable() {
}
}
GL45TextureTable* GL45Backend::syncGPUObject(const TextureTablePointer& textureTablePointer) {
const auto& textureTable = *textureTablePointer;
// Find the target handles
auto textures = textureTable.getTextures();
bool handlesComplete = true;
GL45TextureTable::HandlesArray handles{};
GL45TextureTable::BindlessArray 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);
auto gltexture = (GL45Texture*)syncGPUObject(texture);
if (!gltexture) {
handlesComplete = false;
continue;
}
auto handle = gltexture->getHandle();
memcpy(&handles[i], &handle, sizeof(handle));
handles[i] = gltexture->getBindless();
}
// 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);
if (!object) {
object = new GL45TextureTable(shared_from_this(), textureTable);
}
object->update(handles);
return object;
}

View file

@ -27,6 +27,7 @@ using namespace gpu;
using namespace gpu::gl;
using namespace gpu::gl45;
using GL45Texture = GL45Backend::GL45Texture;
using GL45VariableAllocationTexture = GL45Backend::GL45VariableAllocationTexture;
GL45VariableAllocationTexture::GL45VariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45Texture(backend, texture) {
@ -40,6 +41,12 @@ GL45VariableAllocationTexture::~GL45VariableAllocationTexture() {
Backend::textureResourcePopulatedGPUMemSize.update(_populatedSize, 0);
}
const GL45Texture::Bindless& GL45VariableAllocationTexture::getBindless() const {
auto& result = Parent::getBindless();
_bindless.minMip = _populatedMip - _allocatedMip;
return result;
}
Size GL45VariableAllocationTexture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const uvec3& size, uint32_t yOffset, GLenum internalFormat, GLenum format, GLenum type, Size sourceSize, const void* sourcePointer) const {
Size amountCopied = 0;
amountCopied = Parent::copyMipFaceLinesFromTexture(mip, face, size, yOffset, internalFormat, format, type, sourceSize, sourcePointer);
@ -127,7 +134,9 @@ Size GL45ResourceTexture::copyMipsFromTexture() {
void GL45ResourceTexture::syncSampler() const {
Parent::syncSampler();
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip);
if (!isBindless()) {
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip);
}
}
void GL45ResourceTexture::promote() {
@ -137,6 +146,10 @@ void GL45ResourceTexture::promote() {
uint16_t targetAllocatedMip = _allocatedMip - std::min<uint16_t>(_allocatedMip, 2);
targetAllocatedMip = std::max<uint16_t>(_minAllocatedMip, targetAllocatedMip);
if (isBindless()) {
releaseBindless();
}
GLuint oldId = _id;
auto oldSize = _size;
uint16_t oldAllocatedMip = _allocatedMip;
@ -170,6 +183,10 @@ void GL45ResourceTexture::demote() {
auto oldSize = _size;
auto oldPopulatedMip = _populatedMip;
if (isBindless()) {
releaseBindless();
}
// allocate new texture
const_cast<GLuint&>(_id) = allocate(_gpuObject);
uint16_t oldAllocatedMip = _allocatedMip;

View file

@ -17,8 +17,10 @@
#include <QMetaType>
#include <QUrl>
#include <functional>
#include <shared/Storage.h>
#include <shared/FileCache.h>
#include <RegisteredMetaTypes.h>
#include "Forward.h"
#include "Resource.h"
#include "Metric.h"
@ -126,12 +128,23 @@ public:
uint8 _wrapModeV = WRAP_REPEAT;
uint8 _wrapModeW = WRAP_REPEAT;
uint8 _mipOffset = 0;
uint8 _minMip = 0;
uint8 _maxMip = MAX_MIP_LEVEL;
Desc() {}
Desc(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _filter(filter), _wrapModeU(wrap), _wrapModeV(wrap), _wrapModeW(wrap) {}
bool operator==(const Desc& other) const {
return _borderColor == other._borderColor &&
_maxAnisotropy == other._maxAnisotropy &&
_filter == other._filter &&
_comparisonFunc == other._comparisonFunc &&
_wrapModeU == other._wrapModeU &&
_wrapModeV == other._wrapModeV &&
_wrapModeW == other._wrapModeW &&
_minMip == other._minMip &&
_maxMip == other._maxMip;
}
};
Sampler() {}
@ -151,11 +164,17 @@ public:
ComparisonFunction getComparisonFunction() const { return ComparisonFunction(_desc._comparisonFunc); }
bool doComparison() const { return getComparisonFunction() != ALWAYS; }
uint8 getMipOffset() const { return _desc._mipOffset; }
uint8 getMinMip() const { return _desc._minMip; }
uint8 getMaxMip() const { return _desc._maxMip; }
const Desc& getDesc() const { return _desc; }
bool operator==(const Sampler& other) const {
return _desc == other._desc;
}
bool operator!=(const Sampler& other) const {
return !(*this == other);
}
protected:
Desc _desc;
};
@ -667,6 +686,17 @@ typedef std::shared_ptr< TextureSource > TextureSourcePointer;
};
namespace std {
template<> struct hash<gpu::Sampler> {
size_t operator()(const gpu::Sampler& sampler) const noexcept {
size_t result = 0;
const auto& desc = sampler.getDesc();
hash_combine(result, desc._comparisonFunc, desc._filter, desc._maxAnisotropy, desc._maxMip, desc._minMip, desc._wrapModeU, desc._wrapModeV, desc._wrapModeW);
return result;
}
};
}
Q_DECLARE_METATYPE(gpu::TexturePointer)
#endif

View file

@ -18,7 +18,6 @@ class TextureTable {
public:
static const size_t COUNT = 8;
using Array = std::array<TexturePointer, COUNT>;
using Array = std::array<TexturePointer, COUNT>;
TextureTable();
TextureTable(const std::initializer_list<TexturePointer>& textures);
TextureTable(const std::array<TexturePointer, COUNT>& textures);

View file

@ -25,7 +25,4 @@ struct GPUTextureTable {
#endif
<@endif@>