Merge pull request #12566 from jherico/bindless

Bindless Textures
This commit is contained in:
Sam Gateau 2018-04-03 10:14:12 -07:00 committed by GitHub
commit 987aa40783
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 657 additions and 74 deletions

View file

@ -55,6 +55,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
(&::gpu::gl::GLBackend::do_setUniformBuffer), (&::gpu::gl::GLBackend::do_setUniformBuffer),
(&::gpu::gl::GLBackend::do_setResourceBuffer), (&::gpu::gl::GLBackend::do_setResourceBuffer),
(&::gpu::gl::GLBackend::do_setResourceTexture), (&::gpu::gl::GLBackend::do_setResourceTexture),
(&::gpu::gl::GLBackend::do_setResourceTextureTable),
(&::gpu::gl::GLBackend::do_setResourceFramebufferSwapChainTexture), (&::gpu::gl::GLBackend::do_setResourceFramebufferSwapChainTexture),
(&::gpu::gl::GLBackend::do_setFramebuffer), (&::gpu::gl::GLBackend::do_setFramebuffer),

View file

@ -40,7 +40,6 @@
#endif #endif
// Let these be configured by the one define picked above // Let these be configured by the one define picked above
#ifdef GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE #ifdef GPU_STEREO_TECHNIQUE_DOUBLED_SIMPLE
#define GPU_STEREO_DRAWCALL_DOUBLED #define GPU_STEREO_DRAWCALL_DOUBLED
@ -102,6 +101,12 @@ public:
static const int MAX_NUM_RESOURCE_TEXTURES = 16; static const int MAX_NUM_RESOURCE_TEXTURES = 16;
size_t getMaxNumResourceTextures() const { return MAX_NUM_RESOURCE_TEXTURES; } 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 // Draw Stage
virtual void do_draw(const Batch& batch, size_t paramOffset) = 0; virtual void do_draw(const Batch& batch, size_t paramOffset) = 0;
virtual void do_drawIndexed(const Batch& batch, size_t paramOffset) = 0; virtual void do_drawIndexed(const Batch& batch, size_t paramOffset) = 0;
@ -130,6 +135,7 @@ public:
// Resource Stage // Resource Stage
virtual void do_setResourceBuffer(const Batch& batch, size_t paramOffset) final; virtual void do_setResourceBuffer(const Batch& batch, size_t paramOffset) final;
virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final; virtual void do_setResourceTexture(const Batch& batch, size_t paramOffset) final;
virtual void do_setResourceTextureTable(const Batch& batch, size_t paramOffset);
virtual void do_setResourceFramebufferSwapChainTexture(const Batch& batch, size_t paramOffset) final; virtual void do_setResourceFramebufferSwapChainTexture(const Batch& batch, size_t paramOffset) final;
// Pipeline Stage // Pipeline Stage
@ -230,6 +236,10 @@ protected:
void recycle() const override; void recycle() const override;
// FIXME instead of a single flag, create a features struct similar to
// https://www.khronos.org/registry/vulkan/specs/1.0/man/html/VkPhysicalDeviceFeatures.html
virtual bool supportsBindless() const { return false; }
static const size_t INVALID_OFFSET = (size_t)-1; static const size_t INVALID_OFFSET = (size_t)-1;
bool _inRenderTransferPass { false }; bool _inRenderTransferPass { false };
int32_t _uboAlignment { 0 }; int32_t _uboAlignment { 0 };
@ -389,6 +399,10 @@ protected:
virtual bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) = 0; virtual bool bindResourceBuffer(uint32_t slot, BufferPointer& buffer) = 0;
virtual void releaseResourceBuffer(uint32_t slot) = 0; virtual void releaseResourceBuffer(uint32_t slot) = 0;
// Helper function that provides common code used by do_setResourceTexture and
// do_setResourceTextureTable (in non-bindless mode)
void bindResourceTexture(uint32_t slot, const TexturePointer& texture);
// update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s // update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s
void releaseResourceTexture(uint32_t slot); void releaseResourceTexture(uint32_t slot);

View file

@ -1,4 +1,4 @@
// //
// GLBackendPipeline.cpp // GLBackendPipeline.cpp
// libraries/gpu/src/gpu // libraries/gpu/src/gpu
// //
@ -9,6 +9,8 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "GLBackend.h" #include "GLBackend.h"
#include <gpu/TextureTable.h>
#include "GLShared.h" #include "GLShared.h"
#include "GLPipeline.h" #include "GLPipeline.h"
#include "GLShader.h" #include "GLShader.h"
@ -247,8 +249,11 @@ void GLBackend::do_setResourceTexture(const Batch& batch, size_t paramOffset) {
return; return;
} }
TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); const auto& resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
bindResourceTexture(slot, resourceTexture);
}
void GLBackend::bindResourceTexture(uint32_t slot, const TexturePointer& resourceTexture) {
if (!resourceTexture) { if (!resourceTexture) {
releaseResourceTexture(slot); releaseResourceTexture(slot);
return; return;
@ -306,6 +311,19 @@ void GLBackend::setResourceTexture(unsigned int slot, const TexturePointer& reso
} }
} }
void GLBackend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) {
const auto& textureTablePointer = batch._textureTables.get(batch._params[paramOffset]._uint);
if (!textureTablePointer) {
return;
}
const auto& textureTable = *textureTablePointer;
const auto& textures = textureTable.getTextures();
for (GLuint slot = 0; slot < textures.size(); ++slot) {
bindResourceTexture(slot, textures[slot]);
}
}
int GLBackend::ResourceStageState::findEmptyTextureSlot() const { int GLBackend::ResourceStageState::findEmptyTextureSlot() const {
// start from the end of the slots, try to find an empty one that can be used // start from the end of the slots, try to find an empty one that can be used
for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) { for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) {
@ -315,4 +333,3 @@ int GLBackend::ResourceStageState::findEmptyTextureSlot() const {
} }
return -1; return -1;
} }

View file

@ -78,6 +78,11 @@ R"SHADER(
#endif #endif
}; };
// TextureTable specific defines
static const std::string textureTableVersion {
"#extension GL_ARB_bindless_texture : require\n#define GPU_TEXTURE_TABLE_BINDLESS\n"
};
// Versions specific of the shader // Versions specific of the shader
static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { { static const std::array<std::string, GLShader::NumVersions> VERSION_DEFINES { {
"", "",
@ -96,9 +101,9 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co
auto& shaderObject = shaderObjects[version]; auto& shaderObject = shaderObjects[version];
std::string shaderDefines = getBackendShaderHeader() + "\n" std::string shaderDefines = getBackendShaderHeader() + "\n"
+ (supportsBindless() ? textureTableVersion : "\n")
+ DOMAIN_DEFINES[shader.getType()] + "\n" + DOMAIN_DEFINES[shader.getType()] + "\n"
+ VERSION_DEFINES[version]; + VERSION_DEFINES[version];
if (handler) { if (handler) {
bool retest = true; bool retest = true;
std::string currentSrc = shaderSource; std::string currentSrc = shaderSource;
@ -120,7 +125,7 @@ GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::Co
compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message); compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderDefines, shaderObject.glshader, compilationLogs[version].message);
} }
if (!compilationLogs[version].compiled) { if (!compilationLogs[version].compiled) {
qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str(); qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str();
shader.setCompilationLogs(compilationLogs); shader.setCompilationLogs(compilationLogs);
return nullptr; return nullptr;

View file

@ -167,7 +167,6 @@ void GL41Texture::syncSampler() const {
glTexParameteri(_target, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]); glTexParameteri(_target, GL_TEXTURE_WRAP_R, WRAP_MODES[sampler.getWrapModeW()]);
glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, (const float*)&sampler.getBorderColor()); 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_MIN_LOD, (float)sampler.getMinMip());
glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); 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 { void GL41FixedAllocationTexture::syncSampler() const {
Parent::syncSampler(); Parent::syncSampler();
const Sampler& sampler = _gpuObject.getSampler(); 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_MIN_LOD, (float)sampler.getMinMip());
glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.0f : sampler.getMaxMip())); glTexParameterf(_target, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.0f : sampler.getMaxMip()));
} }
@ -610,4 +606,3 @@ GL41ResourceTexture::GL41ResourceTexture(const std::weak_ptr<GLBackend>& backend
GL41ResourceTexture::~GL41ResourceTexture() { GL41ResourceTexture::~GL41ResourceTexture() {
} }

View file

@ -16,9 +16,11 @@
#include <gpu/gl/GLTexture.h> #include <gpu/gl/GLTexture.h>
#include <thread> #include <thread>
#include <gpu/TextureTable.h>
#define INCREMENTAL_TRANSFER 0 #define INCREMENTAL_TRANSFER 0
#define GPU_SSBO_TRANSFORM_OBJECT 1 #define GPU_SSBO_TRANSFORM_OBJECT 1
#define GPU_BINDLESS_TEXTURES 0
namespace gpu { namespace gl45 { namespace gpu { namespace gl45 {
@ -31,6 +33,9 @@ class GL45Backend : public GLBackend {
friend class Context; friend class Context;
public: public:
#if GPU_BINDLESS_TEXTURES
virtual bool supportsBindless() const override { return true; }
#endif
#ifdef GPU_SSBO_TRANSFORM_OBJECT #ifdef GPU_SSBO_TRANSFORM_OBJECT
static const GLint TRANSFORM_OBJECT_SLOT { 14 }; // SSBO binding slot static const GLint TRANSFORM_OBJECT_SLOT { 14 }; // SSBO binding slot
@ -58,8 +63,62 @@ public:
void generateMips() const override; 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; 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; void syncSampler() const override;
#if GPU_BINDLESS_TEXTURES
bool isBindless() const {
return _bindless.operator bool();
}
struct Bindless {
uint64_t handle{ 0 };
uint32_t minMip{ 0 };
uint32_t sampler{ 0 };
bool operator==(const Bindless& other) const {
return handle == other.handle && minMip == other.minMip && sampler == other.sampler;
}
bool operator!=(const Bindless& other) const {
return !(*this == other);
}
operator bool() const {
return handle != 0;
}
};
virtual const Bindless& getBindless() const;
void releaseBindless() const;
void recreateBindless() const;
private:
mutable Bindless _bindless;
#endif
static Sampler getInvalidSampler();
// This stores the texture handle (64 bits) in xy, the min mip available in z, and the sampler ID in w
mutable Sampler _cachedSampler{ getInvalidSampler() };
}; };
#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 // Textures that have fixed allocation sizes and cannot be managed at runtime
// //
@ -74,6 +133,7 @@ public:
protected: protected:
Size size() const override { return _size; } Size size() const override { return _size; }
void allocateStorage() const; void allocateStorage() const;
void syncSampler() const override; void syncSampler() const override;
const Size _size { 0 }; const Size _size { 0 };
@ -104,7 +164,6 @@ public:
friend class GL45Backend; friend class GL45Backend;
using PromoteLambda = std::function<void()>; using PromoteLambda = std::function<void()>;
protected: protected:
GL45VariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture); GL45VariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture);
~GL45VariableAllocationTexture(); ~GL45VariableAllocationTexture();
@ -114,6 +173,9 @@ public:
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; 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; void copyTextureMipsInGPUMem(GLuint srcId, GLuint destId, uint16_t srcMipOffset, uint16_t destMipOffset, uint16_t populatedMips) override;
#if GPU_BINDLESS_TEXTURES
virtual const Bindless& getBindless() const override;
#endif
}; };
class GL45ResourceTexture : public GL45VariableAllocationTexture { class GL45ResourceTexture : public GL45VariableAllocationTexture {
@ -182,6 +244,7 @@ protected:
GLuint getQueryID(const QueryPointer& query) override; GLuint getQueryID(const QueryPointer& query) override;
GLQuery* syncGPUObject(const Query& query) override; GLQuery* syncGPUObject(const Query& query) override;
// Draw Stage // Draw Stage
void do_draw(const Batch& batch, size_t paramOffset) override; void do_draw(const Batch& batch, size_t paramOffset) override;
void do_drawIndexed(const Batch& batch, size_t paramOffset) override; void do_drawIndexed(const Batch& batch, size_t paramOffset) override;
@ -213,6 +276,12 @@ protected:
// Texture Management Stage // Texture Management Stage
void initTextureManagementStage() override; void initTextureManagementStage() override;
#if GPU_BINDLESS_TEXTURES
GL45TextureTable* syncGPUObject(const TextureTablePointer& textureTable);
// Resource stage
void do_setResourceTextureTable(const Batch& batch, size_t paramOffset) override;
#endif
}; };
} } } }

View file

@ -165,6 +165,11 @@ void GL45Backend::makeProgramBindings(ShaderObject& shaderObject) {
shaderObject.transformCameraSlot = gpu::TRANSFORM_CAMERA_SLOT; 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(); (void)CHECK_GL_ERROR();
} }

View file

@ -20,14 +20,17 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <gl/Context.h>
#include <gpu/TextureTable.h>
#include <gpu/gl/GLTexelFormat.h> #include <gpu/gl/GLTexelFormat.h>
using namespace gpu; using namespace gpu;
using namespace gpu::gl; using namespace gpu::gl;
using namespace gpu::gl45; using namespace gpu::gl45;
#define SPARSE_PAGE_SIZE_OVERHEAD_ESTIMATE 1.3f
#define MAX_RESOURCE_TEXTURES_PER_FRAME 2 #define MAX_RESOURCE_TEXTURES_PER_FRAME 2
#define FORCE_STRICT_TEXTURE 0
#define ENABLE_SPARSE_TEXTURE 0
GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) { GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) {
if (!texturePointer) { if (!texturePointer) {
@ -51,14 +54,18 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) {
object = new GL45AttachmentTexture(shared_from_this(), texture); object = new GL45AttachmentTexture(shared_from_this(), texture);
break; break;
#if FORCE_STRICT_TEXTURE
case TextureUsageType::RESOURCE:
#endif
case TextureUsageType::STRICT_RESOURCE: case TextureUsageType::STRICT_RESOURCE:
qCDebug(gpugllogging) << "Strict texture " << texture.source().c_str(); qCDebug(gpugllogging) << "Strict texture " << texture.source().c_str();
object = new GL45StrictResourceTexture(shared_from_this(), texture); object = new GL45StrictResourceTexture(shared_from_this(), texture);
break; break;
#if !FORCE_STRICT_TEXTURE
case TextureUsageType::RESOURCE: { case TextureUsageType::RESOURCE: {
if (GL45VariableAllocationTexture::_frameTexturesCreated < MAX_RESOURCE_TEXTURES_PER_FRAME) { if (GL45VariableAllocationTexture::_frameTexturesCreated < MAX_RESOURCE_TEXTURES_PER_FRAME) {
#if 0 #if ENABLE_SPARSE_TEXTURE
if (isTextureManagementSparseEnabled() && GL45Texture::isSparseEligible(texture)) { if (isTextureManagementSparseEnabled() && GL45Texture::isSparseEligible(texture)) {
object = new GL45SparseResourceTexture(shared_from_this(), texture); object = new GL45SparseResourceTexture(shared_from_this(), texture);
} else { } else {
@ -76,7 +83,7 @@ GLTexture* GL45Backend::syncGPUObject(const TexturePointer& texturePointer) {
} }
break; break;
} }
#endif
default: default:
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
@ -114,6 +121,61 @@ void GL45Backend::initTextureManagementStage() {
using GL45Texture = GL45Backend::GL45Texture; 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;
Sampler GL45Texture::getInvalidSampler() {
static Sampler INVALID_SAMPLER;
static std::once_flag once;
std::call_once(once, [] {
Sampler::Desc invalidDesc;
invalidDesc._borderColor = vec4(-1.0f);
INVALID_SAMPLER = Sampler(invalidDesc);
});
return INVALID_SAMPLER;
}
GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture& texture)
: GLTexture(backend, texture, allocate(texture)) { : GLTexture(backend, texture, allocate(texture)) {
} }
@ -121,10 +183,10 @@ GL45Texture::GL45Texture(const std::weak_ptr<GLBackend>& backend, const Texture&
GLuint GL45Texture::allocate(const Texture& texture) { GLuint GL45Texture::allocate(const Texture& texture) {
GLuint result; GLuint result;
glCreateTextures(getGLTextureType(texture), 1, &result); glCreateTextures(getGLTextureType(texture), 1, &result);
#ifdef DEBUG if (::gl::Context::enableDebugLogger()) {
auto source = texture.source(); auto source = texture.source();
glObjectLabel(GL_TEXTURE, result, (GLsizei)source.length(), source.data()); glObjectLabel(GL_TEXTURE, result, (GLsizei)source.length(), source.data());
#endif }
return result; return result;
} }
@ -189,8 +251,50 @@ Size GL45Texture::copyMipFaceLinesFromTexture(uint16_t mip, uint8_t face, const
return amountCopied; return amountCopied;
} }
#if GPU_BINDLESS_TEXTURES
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();
} else {
// Once a texture is about to become bindless, it's base mip level MUST be set to 0
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, 0);
}
_bindless.sampler = SAMPLER_CACHE.getGLSampler(_cachedSampler);
_bindless.handle = glGetTextureSamplerHandleARB(_id, _bindless.sampler);
glMakeTextureHandleResidentARB(_bindless.handle);
}
const GL45Texture::Bindless& GL45Texture::getBindless() const {
if (!_bindless) {
recreateBindless();
}
return _bindless;
}
#endif
void GL45Texture::syncSampler() const { void GL45Texture::syncSampler() const {
const Sampler& sampler = _gpuObject.getSampler(); const Sampler& sampler = _gpuObject.getSampler();
if (_cachedSampler == sampler) {
return;
}
_cachedSampler = sampler;
#if GPU_BINDLESS_TEXTURES
if (isBindless()) {
recreateBindless();
return;
}
#endif
const auto& fm = FILTER_MODES[sampler.getFilter()]; const auto& fm = FILTER_MODES[sampler.getFilter()];
glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter); glTextureParameteri(_id, GL_TEXTURE_MIN_FILTER, fm.minFilter);
@ -214,6 +318,8 @@ void GL45Texture::syncSampler() const {
glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
} }
// Fixed allocation textures, used for strict resources & framebuffer attachments
using GL45FixedAllocationTexture = GL45Backend::GL45FixedAllocationTexture; using GL45FixedAllocationTexture = GL45Backend::GL45FixedAllocationTexture;
GL45FixedAllocationTexture::GL45FixedAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45Texture(backend, texture), _size(texture.evalTotalSize()) { GL45FixedAllocationTexture::GL45FixedAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45Texture(backend, texture), _size(texture.evalTotalSize()) {
@ -238,8 +344,6 @@ void GL45FixedAllocationTexture::allocateStorage() const {
void GL45FixedAllocationTexture::syncSampler() const { void GL45FixedAllocationTexture::syncSampler() const {
Parent::syncSampler(); Parent::syncSampler();
const Sampler& sampler = _gpuObject.getSampler(); 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_MIN_LOD, (float)sampler.getMinMip());
glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip())); glTextureParameterf(_id, GL_TEXTURE_MAX_LOD, (sampler.getMaxMip() == Sampler::MAX_MIP_LEVEL ? 1000.f : sampler.getMaxMip()));
} }
@ -275,6 +379,9 @@ GL45StrictResourceTexture::GL45StrictResourceTexture(const std::weak_ptr<GLBacke
if (texture.isAutogenerateMips()) { if (texture.isAutogenerateMips()) {
generateMips(); generateMips();
} }
// Re-sync the sampler to force access to the new mip level
syncSampler();
} }
GL45StrictResourceTexture::~GL45StrictResourceTexture() { GL45StrictResourceTexture::~GL45StrictResourceTexture() {
@ -282,3 +389,87 @@ GL45StrictResourceTexture::~GL45StrictResourceTexture() {
Backend::textureResidentGPUMemSize.update(size(), 0); Backend::textureResidentGPUMemSize.update(size(), 0);
} }
// Encapsulate bindless textures
#if GPU_BINDLESS_TEXTURES
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)
: Parent(backend, textureTable, allocate()){
Backend::setGPUObject(textureTable, this);
// FIXME include these in overall buffer storage reporting
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) {
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 defaultTextures = gpu::TextureTable::getDefault()->getTextures();
auto textures = textureTable.getTextures();
GL45TextureTable::BindlessArray handles{};
for (size_t i = 0; i < textures.size(); ++i) {
auto texture = textures[i];
if (!texture) {
texture = defaultTextures[i];
}
if (!texture) {
continue;
}
// FIXME what if we have a non-transferrable texture here?
auto gltexture = (GL45Texture*)syncGPUObject(texture);
if (!gltexture) {
continue;
}
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 = new GL45TextureTable(shared_from_this(), textureTable);
}
object->update(handles);
return object;
}
void GL45Backend::do_setResourceTextureTable(const Batch& batch, size_t paramOffset) {
auto textureTablePointer = batch._textureTables.get(batch._params[paramOffset]._uint);
if (!textureTablePointer) {
return;
}
auto slot = batch._params[paramOffset + 1]._uint;
GL45TextureTable* glTextureTable = syncGPUObject(textureTablePointer);
if (glTextureTable) {
glBindBufferBase(GL_UNIFORM_BUFFER, slot + GLBackend::RESOURCE_TABLE_TEXTURE_SLOT_OFFSET, glTextureTable->_id);
}
}
#endif

View file

@ -27,6 +27,7 @@ using namespace gpu;
using namespace gpu::gl; using namespace gpu::gl;
using namespace gpu::gl45; using namespace gpu::gl45;
using GL45Texture = GL45Backend::GL45Texture;
using GL45VariableAllocationTexture = GL45Backend::GL45VariableAllocationTexture; using GL45VariableAllocationTexture = GL45Backend::GL45VariableAllocationTexture;
GL45VariableAllocationTexture::GL45VariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45Texture(backend, texture) { GL45VariableAllocationTexture::GL45VariableAllocationTexture(const std::weak_ptr<GLBackend>& backend, const Texture& texture) : GL45Texture(backend, texture) {
@ -40,6 +41,17 @@ GL45VariableAllocationTexture::~GL45VariableAllocationTexture() {
Backend::textureResourcePopulatedGPUMemSize.update(_populatedSize, 0); Backend::textureResourcePopulatedGPUMemSize.update(_populatedSize, 0);
} }
#if GPU_BINDLESS_TEXTURES
const GL45Texture::Bindless& GL45VariableAllocationTexture::getBindless() const {
// The parent call may re-initialize the _bindless member, so we need to call it first
const auto& result = Parent::getBindless();
// Make sure the referenced structure has the correct minimum available mip value
_bindless.minMip = _populatedMip - _allocatedMip;
// Now return the result
return result;
}
#endif
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 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; Size amountCopied = 0;
amountCopied = Parent::copyMipFaceLinesFromTexture(mip, face, size, yOffset, internalFormat, format, type, sourceSize, sourcePointer); amountCopied = Parent::copyMipFaceLinesFromTexture(mip, face, size, yOffset, internalFormat, format, type, sourceSize, sourcePointer);
@ -127,7 +139,13 @@ Size GL45ResourceTexture::copyMipsFromTexture() {
void GL45ResourceTexture::syncSampler() const { void GL45ResourceTexture::syncSampler() const {
Parent::syncSampler(); Parent::syncSampler();
#if GPU_BINDLESS_TEXTURES
if (!isBindless()) {
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip);
}
#else
glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip); glTextureParameteri(_id, GL_TEXTURE_BASE_LEVEL, _populatedMip - _allocatedMip);
#endif
} }
void GL45ResourceTexture::promote() { void GL45ResourceTexture::promote() {
@ -137,6 +155,13 @@ void GL45ResourceTexture::promote() {
uint16_t targetAllocatedMip = _allocatedMip - std::min<uint16_t>(_allocatedMip, 2); uint16_t targetAllocatedMip = _allocatedMip - std::min<uint16_t>(_allocatedMip, 2);
targetAllocatedMip = std::max<uint16_t>(_minAllocatedMip, targetAllocatedMip); targetAllocatedMip = std::max<uint16_t>(_minAllocatedMip, targetAllocatedMip);
#if GPU_BINDLESS_TEXTURES
bool bindless = isBindless();
if (bindless) {
releaseBindless();
}
#endif
GLuint oldId = _id; GLuint oldId = _id;
auto oldSize = _size; auto oldSize = _size;
uint16_t oldAllocatedMip = _allocatedMip; uint16_t oldAllocatedMip = _allocatedMip;
@ -150,10 +175,17 @@ void GL45ResourceTexture::promote() {
// copy pre-existing mips // copy pre-existing mips
copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip); copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip);
#if GPU_BINDLESS_TEXTURES
if (bindless) {
getBindless();
}
#endif
// destroy the old texture // destroy the old texture
glDeleteTextures(1, &oldId); glDeleteTextures(1, &oldId);
// Update sampler // Update sampler
_cachedSampler = getInvalidSampler();
syncSampler(); syncSampler();
// update the memory usage // update the memory usage
@ -170,6 +202,13 @@ void GL45ResourceTexture::demote() {
auto oldSize = _size; auto oldSize = _size;
auto oldPopulatedMip = _populatedMip; auto oldPopulatedMip = _populatedMip;
#if GPU_BINDLESS_TEXTURES
bool bindless = isBindless();
if (bindless) {
releaseBindless();
}
#endif
// allocate new texture // allocate new texture
const_cast<GLuint&>(_id) = allocate(_gpuObject); const_cast<GLuint&>(_id) = allocate(_gpuObject);
uint16_t oldAllocatedMip = _allocatedMip; uint16_t oldAllocatedMip = _allocatedMip;
@ -179,10 +218,17 @@ void GL45ResourceTexture::demote() {
// copy pre-existing mips // copy pre-existing mips
copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip); copyTextureMipsInGPUMem(oldId, _id, oldAllocatedMip, _allocatedMip, _populatedMip);
#if GPU_BINDLESS_TEXTURES
if (bindless) {
getBindless();
}
#endif
// destroy the old texture // destroy the old texture
glDeleteTextures(1, &oldId); glDeleteTextures(1, &oldId);
// Update sampler // Update sampler
_cachedSampler = getInvalidSampler();
syncSampler(); syncSampler();
// update the memory usage // update the memory usage

View file

@ -75,6 +75,7 @@ Batch::Batch(const Batch& batch_) {
_buffers._items.swap(batch._buffers._items); _buffers._items.swap(batch._buffers._items);
_textures._items.swap(batch._textures._items); _textures._items.swap(batch._textures._items);
_textureTables._items.swap(batch._textureTables._items);
_streamFormats._items.swap(batch._streamFormats._items); _streamFormats._items.swap(batch._streamFormats._items);
_transforms._items.swap(batch._transforms._items); _transforms._items.swap(batch._transforms._items);
_pipelines._items.swap(batch._pipelines._items); _pipelines._items.swap(batch._pipelines._items);
@ -113,6 +114,7 @@ void Batch::clear() {
_data.clear(); _data.clear();
_buffers.clear(); _buffers.clear();
_textures.clear(); _textures.clear();
_textureTables.clear();
_streamFormats.clear(); _streamFormats.clear();
_transforms.clear(); _transforms.clear();
_pipelines.clear(); _pipelines.clear();
@ -337,6 +339,12 @@ void Batch::setResourceTexture(uint32 slot, const TextureView& view) {
setResourceTexture(slot, view._texture); setResourceTexture(slot, view._texture);
} }
void Batch::setResourceTextureTable(const TextureTablePointer& textureTable, uint32 slot) {
ADD_COMMAND(setResourceTextureTable);
_params.emplace_back(_textureTables.cache(textureTable));
_params.emplace_back(slot);
}
void Batch::setResourceFramebufferSwapChainTexture(uint32 slot, const FramebufferSwapChainPointer& framebuffer, unsigned int swapChainIndex, unsigned int renderBufferSlot) { void Batch::setResourceFramebufferSwapChainTexture(uint32 slot, const FramebufferSwapChainPointer& framebuffer, unsigned int swapChainIndex, unsigned int renderBufferSlot) {
ADD_COMMAND(setResourceFramebufferSwapChainTexture); ADD_COMMAND(setResourceFramebufferSwapChainTexture);

View file

@ -187,6 +187,7 @@ public:
void setResourceTexture(uint32 slot, const TexturePointer& texture); void setResourceTexture(uint32 slot, const TexturePointer& texture);
void setResourceTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView void setResourceTexture(uint32 slot, const TextureView& view); // not a command, just a shortcut from a TextureView
void setResourceTextureTable(const TextureTablePointer& table, uint32 slot = 0);
void setResourceFramebufferSwapChainTexture(uint32 slot, const FramebufferSwapChainPointer& framebuffer, unsigned int swpaChainIndex, unsigned int renderBufferSlot = 0U); // not a command, just a shortcut from a TextureView void setResourceFramebufferSwapChainTexture(uint32 slot, const FramebufferSwapChainPointer& framebuffer, unsigned int swpaChainIndex, unsigned int renderBufferSlot = 0U); // not a command, just a shortcut from a TextureView
// Ouput Stage // Ouput Stage
@ -302,6 +303,7 @@ public:
COMMAND_setUniformBuffer, COMMAND_setUniformBuffer,
COMMAND_setResourceBuffer, COMMAND_setResourceBuffer,
COMMAND_setResourceTexture, COMMAND_setResourceTexture,
COMMAND_setResourceTextureTable,
COMMAND_setResourceFramebufferSwapChainTexture, COMMAND_setResourceFramebufferSwapChainTexture,
COMMAND_setFramebuffer, COMMAND_setFramebuffer,
@ -409,9 +411,10 @@ public:
return offset; return offset;
} }
Data get(uint32 offset) const { const Data& get(uint32 offset) const {
if (offset >= _items.size()) { if (offset >= _items.size()) {
return Data(); static const Data EMPTY;
return EMPTY;
} }
return (_items.data() + offset)->_data; return (_items.data() + offset)->_data;
} }
@ -424,6 +427,7 @@ public:
typedef Cache<BufferPointer>::Vector BufferCaches; typedef Cache<BufferPointer>::Vector BufferCaches;
typedef Cache<TexturePointer>::Vector TextureCaches; typedef Cache<TexturePointer>::Vector TextureCaches;
typedef Cache<TextureTablePointer>::Vector TextureTableCaches;
typedef Cache<Stream::FormatPointer>::Vector StreamFormatCaches; typedef Cache<Stream::FormatPointer>::Vector StreamFormatCaches;
typedef Cache<Transform>::Vector TransformCaches; typedef Cache<Transform>::Vector TransformCaches;
typedef Cache<PipelinePointer>::Vector PipelineCaches; typedef Cache<PipelinePointer>::Vector PipelineCaches;
@ -479,6 +483,7 @@ public:
BufferCaches _buffers; BufferCaches _buffers;
TextureCaches _textures; TextureCaches _textures;
TextureTableCaches _textureTables;
StreamFormatCaches _streamFormats; StreamFormatCaches _streamFormats;
TransformCaches _transforms; TransformCaches _transforms;
PipelineCaches _pipelines; PipelineCaches _pipelines;

View file

@ -91,6 +91,8 @@ namespace gpu {
using Textures = std::vector<TexturePointer>; using Textures = std::vector<TexturePointer>;
class TextureView; class TextureView;
using TextureViews = std::vector<TextureView>; using TextureViews = std::vector<TextureView>;
class TextureTable;
using TextureTablePointer = std::shared_ptr<TextureTable>;
struct StereoState { struct StereoState {
bool isStereo() const { bool isStereo() const {

View file

@ -17,8 +17,10 @@
#include <QMetaType> #include <QMetaType>
#include <QUrl> #include <QUrl>
#include <functional>
#include <shared/Storage.h> #include <shared/Storage.h>
#include <shared/FileCache.h> #include <shared/FileCache.h>
#include <RegisteredMetaTypes.h>
#include "Forward.h" #include "Forward.h"
#include "Resource.h" #include "Resource.h"
#include "Metric.h" #include "Metric.h"
@ -126,12 +128,23 @@ public:
uint8 _wrapModeV = WRAP_REPEAT; uint8 _wrapModeV = WRAP_REPEAT;
uint8 _wrapModeW = WRAP_REPEAT; uint8 _wrapModeW = WRAP_REPEAT;
uint8 _mipOffset = 0;
uint8 _minMip = 0; uint8 _minMip = 0;
uint8 _maxMip = MAX_MIP_LEVEL; uint8 _maxMip = MAX_MIP_LEVEL;
Desc() {} Desc() {}
Desc(const Filter filter, const WrapMode wrap = WRAP_REPEAT) : _filter(filter), _wrapModeU(wrap), _wrapModeV(wrap), _wrapModeW(wrap) {} 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() {} Sampler() {}
@ -151,11 +164,17 @@ public:
ComparisonFunction getComparisonFunction() const { return ComparisonFunction(_desc._comparisonFunc); } ComparisonFunction getComparisonFunction() const { return ComparisonFunction(_desc._comparisonFunc); }
bool doComparison() const { return getComparisonFunction() != ALWAYS; } bool doComparison() const { return getComparisonFunction() != ALWAYS; }
uint8 getMipOffset() const { return _desc._mipOffset; }
uint8 getMinMip() const { return _desc._minMip; } uint8 getMinMip() const { return _desc._minMip; }
uint8 getMaxMip() const { return _desc._maxMip; } uint8 getMaxMip() const { return _desc._maxMip; }
const Desc& getDesc() const { return _desc; } 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: protected:
Desc _desc; Desc _desc;
}; };
@ -666,6 +685,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) Q_DECLARE_METATYPE(gpu::TexturePointer)
#endif #endif

View file

@ -0,0 +1,54 @@
//
// Created by Bradley Austin Davis on 2017/01/25
// Copyright 2013-2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "TextureTable.h"
#include "Texture.h"
#include <shared/GlobalAppProperties.h>
using namespace gpu;
const size_t TextureTable::COUNT{ TEXTURE_TABLE_COUNT };
TextureTable::TextureTable() { }
TextureTable::TextureTable(const std::initializer_list<TexturePointer>& textures) {
auto max = std::min<size_t>(COUNT, textures.size());
auto itr = textures.begin();
size_t index = 0;
while (itr != textures.end() && index < max) {
setTexture(index, *itr);
++index;
}
}
TextureTable::TextureTable(const Array& textures) : _textures(textures) {
}
void TextureTable::setTexture(size_t index, const TexturePointer& texturePointer) {
if (index >= COUNT || _textures[index] == texturePointer) {
return;
}
{
Lock lock(_mutex);
++_stamp;
_textures[index] = texturePointer;
}
}
void TextureTable::setTexture(size_t index, const TextureView& textureView) {
setTexture(index, textureView._texture);
}
TextureTable::Array TextureTable::getTextures() const {
Array result;
{
Lock lock(_mutex);
result = _textures;
}
return result;
}

View file

@ -0,0 +1,44 @@
//
// Created by Bradley Austin Davis on 2017/01/25
// Copyright 2013-2017 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef hifi_gpu_TextureTable_h
#define hifi_gpu_TextureTable_h
#include "Forward.h"
#include <array>
#define TEXTURE_TABLE_COUNT 8
namespace gpu {
class TextureTable {
public:
static const size_t COUNT;
using Array = std::array<TexturePointer, TEXTURE_TABLE_COUNT>;
TextureTable();
TextureTable(const std::initializer_list<TexturePointer>& textures);
TextureTable(const Array& textures);
// Only for gpu::Context
const GPUObjectPointer gpuObject{};
void setTexture(size_t index, const TexturePointer& texturePointer);
void setTexture(size_t index, const TextureView& texturePointer);
Array getTextures() const;
Stamp getStamp() const { return _stamp; }
private:
mutable Mutex _mutex;
Array _textures;
Stamp _stamp{ 1 };
};
}
#endif

View file

@ -0,0 +1,38 @@
<!
// gpu/TextureTable.slh
//
// Created by Sam Gateau on 1/25/17.
// Copyright 2013 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
!>
<@if not GPU_TEXTURE_TABLE_SLH@>
<@def GPU_TEXTURE_TABLE_SLH@>
#ifdef GPU_TEXTURE_TABLE_BINDLESS
#define GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES 8
struct GPUTextureTable {
uvec4 _textures[GPU_TEXTURE_TABLE_MAX_NUM_TEXTURES];
};
#define TextureTable(index, name) layout (std140) uniform gpu_resourceTextureTable##index { GPUTextureTable name; }
#define tableTex(name, slot) sampler2D(name._textures[slot].xy)
#define tableTexMinLod(name, slot) float(name._textures[slot].z)
#define tableTexValue(name, slot, uv) \
tableTexValueLod(tableTex(matTex, albedoMap), tableTexMinLod(matTex, albedoMap), uv)
vec4 tableTexValueLod(sampler2D sampler, float minLod, vec2 uv) {
float queryLod = textureQueryLod(sampler, uv).x;
queryLod = max(minLod, queryLod);
return textureLod(sampler, uv, queryLod);
}
#else
#endif
<@endif@>

View file

@ -504,6 +504,8 @@ TexturePointer Texture::build(const ktx::KTXDescriptor& descriptor) {
gpuktxKeyValue._usage = Texture::Usage::Builder().withColor().withAlpha().build(); gpuktxKeyValue._usage = Texture::Usage::Builder().withColor().withAlpha().build();
} }
auto samplerDesc = gpuktxKeyValue._samplerDesc;
samplerDesc._maxMip = gpu::Sampler::MAX_MIP_LEVEL;
auto texture = create(gpuktxKeyValue._usageType, auto texture = create(gpuktxKeyValue._usageType,
type, type,
texelFormat, texelFormat,
@ -513,7 +515,7 @@ TexturePointer Texture::build(const ktx::KTXDescriptor& descriptor) {
1, // num Samples 1, // num Samples
header.getNumberOfSlices(), header.getNumberOfSlices(),
header.getNumberOfLevels(), header.getNumberOfLevels(),
gpuktxKeyValue._samplerDesc); samplerDesc);
texture->setUsage(gpuktxKeyValue._usage); texture->setUsage(gpuktxKeyValue._usage);
// Assing the mips availables // Assing the mips availables

View file

@ -20,6 +20,7 @@
#include <ColorUtils.h> #include <ColorUtils.h>
#include <gpu/Resource.h> #include <gpu/Resource.h>
#include <gpu/TextureTable.h>
class Transform; class Transform;
@ -361,6 +362,8 @@ public:
const std::string& getModel() const { return _model; } const std::string& getModel() const { return _model; }
void setModel(const std::string& model) { _model = model; } void setModel(const std::string& model) { _model = model; }
const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; }
protected: protected:
std::string _name { "" }; std::string _name { "" };
@ -368,6 +371,7 @@ private:
mutable MaterialKey _key; mutable MaterialKey _key;
mutable UniformBufferView _schemaBuffer; mutable UniformBufferView _schemaBuffer;
mutable UniformBufferView _texMapArrayBuffer; mutable UniformBufferView _texMapArrayBuffer;
mutable gpu::TextureTablePointer _textureTable{ std::make_shared<gpu::TextureTable>() };
TextureMaps _textureMaps; TextureMaps _textureMaps;

View file

@ -48,6 +48,74 @@ TexMapArray getTexMapArray() {
<@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@> <@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@>
<@include gpu/TextureTable.slh@>
#ifdef GPU_TEXTURE_TABLE_BINDLESS
TextureTable(0, matTex);
<!
ALBEDO = 0,
NORMAL, 1
METALLIC, 2
EMISSIVE_LIGHTMAP, 3
ROUGHNESS, 4
OCCLUSION, 5
SCATTERING, 6
!>
<@if withAlbedo@>
#define albedoMap 0
vec4 fetchAlbedoMap(vec2 uv) {
return tableTexValue(matTex, albedoMap, uv);
}
<@endif@>
<@if withRoughness@>
#define roughnessMap 4
float fetchRoughnessMap(vec2 uv) {
return tableTexValue(matTex, roughnessMap, uv).r;
}
<@endif@>
<@if withNormal@>
#define normalMap 1
vec3 fetchNormalMap(vec2 uv) {
return tableTexValue(matTex, normalMap, uv).xyz;
}
<@endif@>
<@if withMetallic@>
#define metallicMap 2
float fetchMetallicMap(vec2 uv) {
return tableTexValue(matTex, metallicMap, uv).r;
}
<@endif@>
<@if withEmissive@>
#define emissiveMap 3
vec3 fetchEmissiveMap(vec2 uv) {
return tableTexValue(matTex, emissiveMap, uv).rgb;
}
<@endif@>
<@if withOcclusion@>
#define occlusionMap 5
float fetchOcclusionMap(vec2 uv) {
return tableTexValue(matTex, occlusionMap, uv).r;
}
<@endif@>
<@if withScattering@>
#define scatteringMap 6
float fetchScatteringMap(vec2 uv) {
float scattering = texture(tableTex(matTex, scatteringMap), uv).r; // boolean scattering for now
return max(((scattering - 0.1) / 0.9), 0.0);
return tableTexValue(matTex, scatteringMap, uv).r; // boolean scattering for now
}
<@endif@>
#else
<@if withAlbedo@> <@if withAlbedo@>
uniform sampler2D albedoMap; uniform sampler2D albedoMap;
vec4 fetchAlbedoMap(vec2 uv) { vec4 fetchAlbedoMap(vec2 uv) {
@ -102,6 +170,8 @@ float fetchScatteringMap(vec2 uv) {
} }
<@endif@> <@endif@>
#endif
<@endfunc@> <@endfunc@>

View file

@ -152,7 +152,7 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) {
batch.setInputStream(0, _drawMesh->getVertexStream()); batch.setInputStream(0, _drawMesh->getVertexStream());
} }
void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const { void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
batch.setModelTransform(_drawTransform); batch.setModelTransform(_drawTransform);
} }

View file

@ -612,7 +612,8 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state) {
#include "RenderPipelines.h" #include "RenderPipelines.h"
#include <model-networking/TextureCache.h> #include <model-networking/TextureCache.h>
void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) { // FIXME find a better way to setup the default textures
void RenderPipelines::bindMaterial(const graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures) {
if (!material) { if (!material) {
return; return;
} }
@ -630,84 +631,65 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batc
numUnlit++; numUnlit++;
} }
if (!enableTextures) { const auto& drawMaterialTextures = material->getTextureTable();
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
return;
}
// Albedo // Albedo
if (materialKey.isAlbedoMap()) { if (materialKey.isAlbedoMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP); auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) { if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView()); drawMaterialTextures->setTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView());
} else { } else {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture()); drawMaterialTextures->setTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture());
} }
} }
// Roughness map // Roughness map
if (materialKey.isRoughnessMap()) { if (materialKey.isRoughnessMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP); auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) { if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView()); drawMaterialTextures->setTexture(ShapePipeline::Slot::ROUGHNESS, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else { } else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture()); drawMaterialTextures->setTexture(ShapePipeline::Slot::ROUGHNESS, textureCache->getWhiteTexture());
} }
} }
// Normal map // Normal map
if (materialKey.isNormalMap()) { if (materialKey.isNormalMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP); auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) { if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView()); drawMaterialTextures->setTexture(ShapePipeline::Slot::NORMAL, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else { } else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture()); drawMaterialTextures->setTexture(ShapePipeline::Slot::NORMAL, textureCache->getBlueTexture());
} }
} }
// Metallic map // Metallic map
if (materialKey.isMetallicMap()) { if (materialKey.isMetallicMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP); auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) { if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView()); drawMaterialTextures->setTexture(ShapePipeline::Slot::METALLIC, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else { } else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture()); drawMaterialTextures->setTexture(ShapePipeline::Slot::METALLIC, textureCache->getBlackTexture());
} }
} }
// Occlusion map // Occlusion map
if (materialKey.isOcclusionMap()) { if (materialKey.isOcclusionMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP); auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) { if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView()); drawMaterialTextures->setTexture(ShapePipeline::Slot::OCCLUSION, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else { } else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture()); drawMaterialTextures->setTexture(ShapePipeline::Slot::OCCLUSION, textureCache->getWhiteTexture());
} }
} }
// Scattering map // Scattering map
if (materialKey.isScatteringMap()) { if (materialKey.isScatteringMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP); auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) { if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView()); drawMaterialTextures->setTexture(ShapePipeline::Slot::SCATTERING, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else { } else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture()); drawMaterialTextures->setTexture(ShapePipeline::Slot::SCATTERING, textureCache->getWhiteTexture());
} }
} }
@ -715,18 +697,19 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer material, gpu::Batc
if (materialKey.isLightmapMap()) { if (materialKey.isLightmapMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP); auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) { if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView()); drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
} else { } else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture()); drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture());
} }
} else if (materialKey.isEmissiveMap()) { } else if (materialKey.isEmissiveMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP); auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP);
if (enableTextures && itr != textureMaps.end() && itr->second->isDefined()) {
if (itr != textureMaps.end() && itr->second->isDefined()) { drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
} else { } else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture()); drawMaterialTextures->setTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
} }
} }
batch.setResourceTextureTable(material->getTextureTable());
} }

View file

@ -15,7 +15,7 @@
class RenderPipelines { class RenderPipelines {
public: public:
static void bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures); static void bindMaterial(const graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures);
}; };