mirror of
https://github.com/love2d/love.git
synced 2026-08-20 04:30:09 +02:00
Add new texel buffer type.
GLSL 3+ shaders can read from texel buffers by declaring a uniform samplerBuffer variable and calling texelFetch with a 0-based index, in the shader code. All attributes in a texel buffer's format array must have the same data format (e.g. all 'floatvec4' formats). Shader:send accepts a texel Buffer for samplerBuffer uniforms. Added 'texelbuffer' to love.graphics.getSupported (requires GLSL 3+ and desktop OpenGL). Added 'texelbuffersize' to love.graphics.getSystemLimits. Returns the max number of values in a texel buffer (array length multiplied by the number of attributes declared in the buffer's format array).
This commit is contained in:
@@ -43,13 +43,18 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
|
|||||||
if (bufferformat.size() == 0)
|
if (bufferformat.size() == 0)
|
||||||
throw love::Exception("Data format must contain values.");
|
throw love::Exception("Data format must contain values.");
|
||||||
|
|
||||||
bool supportsGLSL3 = gfx->getCapabilities().features[Graphics::FEATURE_GLSL3];
|
const auto &caps = gfx->getCapabilities();
|
||||||
|
bool supportsGLSL3 = caps.features[Graphics::FEATURE_GLSL3];
|
||||||
|
|
||||||
bool indexbuffer = settings.typeFlags & TYPEFLAG_INDEX;
|
bool indexbuffer = settings.typeFlags & TYPEFLAG_INDEX;
|
||||||
bool vertexbuffer = settings.typeFlags & TYPEFLAG_VERTEX;
|
bool vertexbuffer = settings.typeFlags & TYPEFLAG_VERTEX;
|
||||||
|
bool texelbuffer = settings.typeFlags & TYPEFLAG_TEXEL;
|
||||||
|
|
||||||
if (!indexbuffer && !vertexbuffer)
|
if (!indexbuffer && !vertexbuffer && !texelbuffer)
|
||||||
throw love::Exception("Buffer must be created with at least one buffer type (index or vertex).");
|
throw love::Exception("Buffer must be created with at least one buffer type (index, vertex, or texel).");
|
||||||
|
|
||||||
|
if (texelbuffer && !caps.features[Graphics::FEATURE_TEXEL_BUFFER])
|
||||||
|
throw love::Exception("Texel buffers are not supported on this system.");
|
||||||
|
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
size_t stride = 0;
|
size_t stride = 0;
|
||||||
@@ -68,6 +73,9 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
|
|||||||
|
|
||||||
if (bufferformat.size() > 1)
|
if (bufferformat.size() > 1)
|
||||||
throw love::Exception("Index buffers only support a single value per element.");
|
throw love::Exception("Index buffers only support a single value per element.");
|
||||||
|
|
||||||
|
if (decl.arrayLength > 0)
|
||||||
|
throw love::Exception("Arrays are not supported in index buffers.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vertexbuffer)
|
if (vertexbuffer)
|
||||||
@@ -83,6 +91,30 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
|
|||||||
|
|
||||||
if ((info.baseType == DATA_BASETYPE_INT || info.baseType == DATA_BASETYPE_UINT) && !supportsGLSL3)
|
if ((info.baseType == DATA_BASETYPE_INT || info.baseType == DATA_BASETYPE_UINT) && !supportsGLSL3)
|
||||||
throw love::Exception("Integer vertex attribute data types require GLSL 3 support.");
|
throw love::Exception("Integer vertex attribute data types require GLSL 3 support.");
|
||||||
|
|
||||||
|
if (decl.name.empty())
|
||||||
|
throw love::Exception("Vertex buffer attributes must have a name.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (texelbuffer)
|
||||||
|
{
|
||||||
|
if (format != bufferformat[0].format)
|
||||||
|
throw love::Exception("All values in a texel buffer must have the same format.");
|
||||||
|
|
||||||
|
if (decl.arrayLength > 0)
|
||||||
|
throw love::Exception("Arrays are not supported in texel buffers.");
|
||||||
|
|
||||||
|
if (info.isMatrix)
|
||||||
|
throw love::Exception("Matrix types are not supported in texel buffers.");
|
||||||
|
|
||||||
|
if (info.baseType == DATA_BASETYPE_BOOL)
|
||||||
|
throw love::Exception("Bool types are not supported in texel buffers.");
|
||||||
|
|
||||||
|
if (info.components == 3)
|
||||||
|
throw love::Exception("3-component formats are not supported in texel buffers.");
|
||||||
|
|
||||||
|
if (info.baseType == DATA_BASETYPE_SNORM)
|
||||||
|
throw love::Exception("Signed normalized formats are not supported in texel buffers.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: alignment
|
// TODO: alignment
|
||||||
@@ -111,6 +143,9 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector<DataDe
|
|||||||
this->arrayStride = stride;
|
this->arrayStride = stride;
|
||||||
this->arrayLength = arraylength;
|
this->arrayLength = arraylength;
|
||||||
this->size = size;
|
this->size = size;
|
||||||
|
|
||||||
|
if (texelbuffer && arraylength * dataMembers.size() > caps.limits[Graphics::LIMIT_TEXEL_BUFFER_SIZE])
|
||||||
|
throw love::Exception("Cannot create texel buffer: total number of values in the buffer (%d * %d) is too large for this system (maximum %d).", (int) dataMembers.size(), (int) arraylength, caps.limits[Graphics::LIMIT_TEXEL_BUFFER_SIZE]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer::~Buffer()
|
Buffer::~Buffer()
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ public:
|
|||||||
TYPEFLAG_NONE = 0,
|
TYPEFLAG_NONE = 0,
|
||||||
TYPEFLAG_VERTEX = 1 << BUFFERTYPE_VERTEX,
|
TYPEFLAG_VERTEX = 1 << BUFFERTYPE_VERTEX,
|
||||||
TYPEFLAG_INDEX = 1 << BUFFERTYPE_INDEX,
|
TYPEFLAG_INDEX = 1 << BUFFERTYPE_INDEX,
|
||||||
|
TYPEFLAG_TEXEL = 1 << BUFFERTYPE_TEXEL,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DataDeclaration
|
struct DataDeclaration
|
||||||
@@ -141,10 +142,6 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill a portion of the buffer with data and marks the range as modified.
|
* Fill a portion of the buffer with data and marks the range as modified.
|
||||||
*
|
|
||||||
* @param offset The offset in the GLBuffer to store the data.
|
|
||||||
* @param size The size of the incoming data.
|
|
||||||
* @param data Pointer to memory to copy data from.
|
|
||||||
*/
|
*/
|
||||||
virtual void fill(size_t offset, size_t size, const void *data) = 0;
|
virtual void fill(size_t offset, size_t size, const void *data) = 0;
|
||||||
|
|
||||||
@@ -153,6 +150,12 @@ public:
|
|||||||
**/
|
**/
|
||||||
virtual void copyTo(size_t offset, size_t size, Buffer *other, size_t otheroffset) = 0;
|
virtual void copyTo(size_t offset, size_t size, Buffer *other, size_t otheroffset) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Texel buffers may use an additional texture handle as well as a buffer
|
||||||
|
* handle.
|
||||||
|
**/
|
||||||
|
virtual ptrdiff_t getTexelBufferHandle() const = 0;
|
||||||
|
|
||||||
static std::vector<DataDeclaration> getCommonFormatDeclaration(CommonFormat format);
|
static std::vector<DataDeclaration> getCommonFormatDeclaration(CommonFormat format);
|
||||||
|
|
||||||
class Mapper
|
class Mapper
|
||||||
|
|||||||
@@ -1932,6 +1932,7 @@ StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM>::Entry Graphics::featur
|
|||||||
{ "glsl3", FEATURE_GLSL3 },
|
{ "glsl3", FEATURE_GLSL3 },
|
||||||
{ "glsl4", FEATURE_GLSL4 },
|
{ "glsl4", FEATURE_GLSL4 },
|
||||||
{ "instancing", FEATURE_INSTANCING },
|
{ "instancing", FEATURE_INSTANCING },
|
||||||
|
{ "texelbuffer", FEATURE_TEXEL_BUFFER },
|
||||||
};
|
};
|
||||||
|
|
||||||
StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM> Graphics::features(Graphics::featureEntries, sizeof(Graphics::featureEntries));
|
StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM> Graphics::features(Graphics::featureEntries, sizeof(Graphics::featureEntries));
|
||||||
@@ -1943,6 +1944,7 @@ StringMap<Graphics::SystemLimit, Graphics::LIMIT_MAX_ENUM>::Entry Graphics::syst
|
|||||||
{ "texturelayers", LIMIT_TEXTURE_LAYERS },
|
{ "texturelayers", LIMIT_TEXTURE_LAYERS },
|
||||||
{ "volumetexturesize", LIMIT_VOLUME_TEXTURE_SIZE },
|
{ "volumetexturesize", LIMIT_VOLUME_TEXTURE_SIZE },
|
||||||
{ "cubetexturesize", LIMIT_CUBE_TEXTURE_SIZE },
|
{ "cubetexturesize", LIMIT_CUBE_TEXTURE_SIZE },
|
||||||
|
{ "texelbuffersize", LIMIT_TEXEL_BUFFER_SIZE },
|
||||||
{ "rendertargets", LIMIT_RENDER_TARGETS },
|
{ "rendertargets", LIMIT_RENDER_TARGETS },
|
||||||
{ "texturemsaa", LIMIT_TEXTURE_MSAA },
|
{ "texturemsaa", LIMIT_TEXTURE_MSAA },
|
||||||
{ "anisotropy", LIMIT_ANISOTROPY },
|
{ "anisotropy", LIMIT_ANISOTROPY },
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ public:
|
|||||||
FEATURE_GLSL3,
|
FEATURE_GLSL3,
|
||||||
FEATURE_GLSL4,
|
FEATURE_GLSL4,
|
||||||
FEATURE_INSTANCING,
|
FEATURE_INSTANCING,
|
||||||
|
FEATURE_TEXEL_BUFFER,
|
||||||
FEATURE_MAX_ENUM
|
FEATURE_MAX_ENUM
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -160,6 +161,7 @@ public:
|
|||||||
LIMIT_VOLUME_TEXTURE_SIZE,
|
LIMIT_VOLUME_TEXTURE_SIZE,
|
||||||
LIMIT_CUBE_TEXTURE_SIZE,
|
LIMIT_CUBE_TEXTURE_SIZE,
|
||||||
LIMIT_TEXTURE_LAYERS,
|
LIMIT_TEXTURE_LAYERS,
|
||||||
|
LIMIT_TEXEL_BUFFER_SIZE,
|
||||||
LIMIT_RENDER_TARGETS,
|
LIMIT_RENDER_TARGETS,
|
||||||
LIMIT_TEXTURE_MSAA,
|
LIMIT_TEXTURE_MSAA,
|
||||||
LIMIT_ANISOTROPY,
|
LIMIT_ANISOTROPY,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ namespace graphics
|
|||||||
{
|
{
|
||||||
|
|
||||||
class Graphics;
|
class Graphics;
|
||||||
|
class Buffer;
|
||||||
|
|
||||||
// A GLSL shader
|
// A GLSL shader
|
||||||
class Shader : public Object, public Resource
|
class Shader : public Object, public Resource
|
||||||
@@ -76,6 +77,7 @@ public:
|
|||||||
UNIFORM_UINT,
|
UNIFORM_UINT,
|
||||||
UNIFORM_BOOL,
|
UNIFORM_BOOL,
|
||||||
UNIFORM_SAMPLER,
|
UNIFORM_SAMPLER,
|
||||||
|
UNIFORM_TEXELBUFFER,
|
||||||
UNIFORM_UNKNOWN,
|
UNIFORM_UNKNOWN,
|
||||||
UNIFORM_MAX_ENUM
|
UNIFORM_MAX_ENUM
|
||||||
};
|
};
|
||||||
@@ -115,6 +117,7 @@ public:
|
|||||||
|
|
||||||
UniformType baseType;
|
UniformType baseType;
|
||||||
TextureType textureType;
|
TextureType textureType;
|
||||||
|
DataBaseType texelBufferType;
|
||||||
bool isDepthSampler;
|
bool isDepthSampler;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
@@ -128,7 +131,11 @@ public:
|
|||||||
|
|
||||||
size_t dataSize;
|
size_t dataSize;
|
||||||
|
|
||||||
Texture **textures;
|
union
|
||||||
|
{
|
||||||
|
Texture **textures;
|
||||||
|
Buffer **buffers;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// The members in here must respect uniform buffer alignment/padding rules.
|
// The members in here must respect uniform buffer alignment/padding rules.
|
||||||
@@ -178,6 +185,7 @@ public:
|
|||||||
virtual void updateUniform(const UniformInfo *info, int count) = 0;
|
virtual void updateUniform(const UniformInfo *info, int count) = 0;
|
||||||
|
|
||||||
virtual void sendTextures(const UniformInfo *info, Texture **textures, int count) = 0;
|
virtual void sendTextures(const UniformInfo *info, Texture **textures, int count) = 0;
|
||||||
|
virtual void sendBuffers(const UniformInfo *info, Buffer **buffers, int count) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets whether a uniform with the specified name exists and is actively
|
* Gets whether a uniform with the specified name exists and is actively
|
||||||
|
|||||||
@@ -35,13 +35,45 @@ namespace graphics
|
|||||||
namespace opengl
|
namespace opengl
|
||||||
{
|
{
|
||||||
|
|
||||||
|
static GLenum getGLFormat(DataFormat format)
|
||||||
|
{
|
||||||
|
switch (format)
|
||||||
|
{
|
||||||
|
case DATAFORMAT_FLOAT: return GL_R32F;
|
||||||
|
case DATAFORMAT_FLOAT_VEC2: return GL_RG32F;
|
||||||
|
case DATAFORMAT_FLOAT_VEC3: return GL_RGB32F;
|
||||||
|
case DATAFORMAT_FLOAT_VEC4: return GL_RGBA32F;
|
||||||
|
case DATAFORMAT_INT32: return GL_R32I;
|
||||||
|
case DATAFORMAT_INT32_VEC2: return GL_RG32I;
|
||||||
|
case DATAFORMAT_INT32_VEC3: return GL_RGB32I;
|
||||||
|
case DATAFORMAT_INT32_VEC4: return GL_RGBA32I;
|
||||||
|
case DATAFORMAT_UINT32: return GL_R32UI;
|
||||||
|
case DATAFORMAT_UINT32_VEC2: return GL_RG32UI;
|
||||||
|
case DATAFORMAT_UINT32_VEC3: return GL_RGB32UI;
|
||||||
|
case DATAFORMAT_UINT32_VEC4: return GL_RGBA32UI;
|
||||||
|
case DATAFORMAT_UNORM8_VEC4: return GL_RGBA8;
|
||||||
|
case DATAFORMAT_INT8_VEC4: return GL_RGBA8I;
|
||||||
|
case DATAFORMAT_UINT8_VEC4: return GL_RGBA8UI;
|
||||||
|
case DATAFORMAT_UNORM16_VEC2: return GL_RG16;
|
||||||
|
case DATAFORMAT_UNORM16_VEC4: return GL_RGBA16;
|
||||||
|
case DATAFORMAT_INT16_VEC2: return GL_RG16I;
|
||||||
|
case DATAFORMAT_INT16_VEC4: return GL_RGBA16I;
|
||||||
|
case DATAFORMAT_UINT16: return GL_R16UI;
|
||||||
|
case DATAFORMAT_UINT16_VEC2: return GL_RG16UI;
|
||||||
|
case DATAFORMAT_UINT16_VEC4: return GL_RGBA16UI;
|
||||||
|
default: return GL_ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Buffer::Buffer(love::graphics::Graphics *gfx, const Settings &settings, const std::vector<DataDeclaration> &format, const void *data, size_t size, size_t arraylength)
|
Buffer::Buffer(love::graphics::Graphics *gfx, const Settings &settings, const std::vector<DataDeclaration> &format, const void *data, size_t size, size_t arraylength)
|
||||||
: love::graphics::Buffer(gfx, settings, format, size, arraylength)
|
: love::graphics::Buffer(gfx, settings, format, size, arraylength)
|
||||||
{
|
{
|
||||||
size = getSize();
|
size = getSize();
|
||||||
arraylength = getArrayLength();
|
arraylength = getArrayLength();
|
||||||
|
|
||||||
if (typeFlags & TYPEFLAG_VERTEX)
|
if (typeFlags & TYPEFLAG_TEXEL)
|
||||||
|
mapType = BUFFERTYPE_TEXEL;
|
||||||
|
else if (typeFlags & TYPEFLAG_VERTEX)
|
||||||
mapType = BUFFERTYPE_VERTEX;
|
mapType = BUFFERTYPE_VERTEX;
|
||||||
else if (typeFlags & TYPEFLAG_INDEX)
|
else if (typeFlags & TYPEFLAG_INDEX)
|
||||||
mapType = BUFFERTYPE_INDEX;
|
mapType = BUFFERTYPE_INDEX;
|
||||||
@@ -62,8 +94,9 @@ Buffer::Buffer(love::graphics::Graphics *gfx, const Settings &settings, const st
|
|||||||
|
|
||||||
if (!load(data != nullptr))
|
if (!load(data != nullptr))
|
||||||
{
|
{
|
||||||
|
unloadVolatile();
|
||||||
delete[] memoryMap;
|
delete[] memoryMap;
|
||||||
throw love::Exception("Could not load vertex buffer (out of VRAM?)");
|
throw love::Exception("Could not create buffer (out of VRAM?)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,31 +108,45 @@ Buffer::~Buffer()
|
|||||||
|
|
||||||
bool Buffer::loadVolatile()
|
bool Buffer::loadVolatile()
|
||||||
{
|
{
|
||||||
|
if (buffer != 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
return load(true);
|
return load(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Buffer::unloadVolatile()
|
void Buffer::unloadVolatile()
|
||||||
{
|
{
|
||||||
mapped = false;
|
mapped = false;
|
||||||
if (vbo != 0)
|
if (buffer != 0)
|
||||||
gl.deleteBuffer(vbo);
|
gl.deleteBuffer(buffer);
|
||||||
vbo = 0;
|
buffer = 0;
|
||||||
|
if (texture != 0)
|
||||||
|
gl.deleteTexture(texture);
|
||||||
|
texture = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Buffer::load(bool restore)
|
bool Buffer::load(bool restore)
|
||||||
{
|
{
|
||||||
glGenBuffers(1, &vbo);
|
|
||||||
gl.bindBuffer(mapType, vbo);
|
|
||||||
|
|
||||||
while (glGetError() != GL_NO_ERROR)
|
while (glGetError() != GL_NO_ERROR)
|
||||||
/* Clear the error buffer. */;
|
/* Clear the error buffer. */;
|
||||||
|
|
||||||
|
glGenBuffers(1, &buffer);
|
||||||
|
gl.bindBuffer(mapType, buffer);
|
||||||
|
|
||||||
// Copy the old buffer only if 'restore' was requested.
|
// Copy the old buffer only if 'restore' was requested.
|
||||||
const GLvoid *src = restore ? memoryMap : nullptr;
|
const GLvoid *src = restore ? memoryMap : nullptr;
|
||||||
|
|
||||||
// Note that if 'src' is '0', no data will be copied.
|
// Note that if 'src' is '0', no data will be copied.
|
||||||
glBufferData(target, (GLsizeiptr) getSize(), src, OpenGL::getGLBufferUsage(getUsage()));
|
glBufferData(target, (GLsizeiptr) getSize(), src, OpenGL::getGLBufferUsage(getUsage()));
|
||||||
|
|
||||||
|
if (getTypeFlags() & TYPEFLAG_TEXEL)
|
||||||
|
{
|
||||||
|
glGenTextures(1, &texture);
|
||||||
|
gl.bindBufferTextureToUnit(texture, 0, false, true);
|
||||||
|
|
||||||
|
glTexBuffer(target, getGLFormat(getDataMember(0).decl.format), buffer);
|
||||||
|
}
|
||||||
|
|
||||||
return (glGetError() == GL_NO_ERROR);
|
return (glGetError() == GL_NO_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +170,7 @@ void Buffer::unmapStatic(size_t offset, size_t size)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// Upload the mapped data to the buffer.
|
// Upload the mapped data to the buffer.
|
||||||
gl.bindBuffer(mapType, vbo);
|
gl.bindBuffer(mapType, buffer);
|
||||||
glBufferSubData(target, (GLintptr) offset, (GLsizeiptr) size, memoryMap + offset);
|
glBufferSubData(target, (GLintptr) offset, (GLsizeiptr) size, memoryMap + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +180,7 @@ void Buffer::unmapStream()
|
|||||||
|
|
||||||
// "orphan" current buffer to avoid implicit synchronisation on the GPU:
|
// "orphan" current buffer to avoid implicit synchronisation on the GPU:
|
||||||
// http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf
|
// http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-AsynchronousBufferTransfers.pdf
|
||||||
gl.bindBuffer(mapType, vbo);
|
gl.bindBuffer(mapType, buffer);
|
||||||
glBufferData(target, (GLsizeiptr) getSize(), nullptr, glusage);
|
glBufferData(target, (GLsizeiptr) getSize(), nullptr, glusage);
|
||||||
|
|
||||||
#if LOVE_WINDOWS
|
#if LOVE_WINDOWS
|
||||||
@@ -224,16 +271,11 @@ void Buffer::fill(size_t offset, size_t size, const void *data)
|
|||||||
setMappedRangeModified(offset, size);
|
setMappedRangeModified(offset, size);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
gl.bindBuffer(mapType, vbo);
|
gl.bindBuffer(mapType, buffer);
|
||||||
glBufferSubData(target, (GLintptr) offset, (GLsizeiptr) size, data);
|
glBufferSubData(target, (GLintptr) offset, (GLsizeiptr) size, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ptrdiff_t Buffer::getHandle() const
|
|
||||||
{
|
|
||||||
return vbo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Buffer::copyTo(size_t offset, size_t size, love::graphics::Buffer *other, size_t otheroffset)
|
void Buffer::copyTo(size_t offset, size_t size, love::graphics::Buffer *other, size_t otheroffset)
|
||||||
{
|
{
|
||||||
other->fill(otheroffset, size, memoryMap + offset);
|
other->fill(otheroffset, size, memoryMap + offset);
|
||||||
|
|||||||
@@ -53,7 +53,9 @@ public:
|
|||||||
void unmap() override;
|
void unmap() override;
|
||||||
void setMappedRangeModified(size_t offset, size_t size) override;
|
void setMappedRangeModified(size_t offset, size_t size) override;
|
||||||
void fill(size_t offset, size_t size, const void *data) override;
|
void fill(size_t offset, size_t size, const void *data) override;
|
||||||
ptrdiff_t getHandle() const override;
|
|
||||||
|
ptrdiff_t getHandle() const override { return buffer; };
|
||||||
|
ptrdiff_t getTexelBufferHandle() const override { return texture; };
|
||||||
|
|
||||||
void copyTo(size_t offset, size_t size, love::graphics::Buffer *other, size_t otheroffset) override;
|
void copyTo(size_t offset, size_t size, love::graphics::Buffer *other, size_t otheroffset) override;
|
||||||
|
|
||||||
@@ -67,8 +69,11 @@ private:
|
|||||||
BufferType mapType = BUFFERTYPE_VERTEX;
|
BufferType mapType = BUFFERTYPE_VERTEX;
|
||||||
GLenum target = 0;
|
GLenum target = 0;
|
||||||
|
|
||||||
// The VBO identifier. Assigned by OpenGL.
|
// The buffer object identifier. Assigned by OpenGL.
|
||||||
GLuint vbo = 0;
|
GLuint buffer = 0;
|
||||||
|
|
||||||
|
// Used for Texel Buffer types.
|
||||||
|
GLuint texture = 0;
|
||||||
|
|
||||||
// A pointer to mapped memory.
|
// A pointer to mapped memory.
|
||||||
char *memoryMap = nullptr;
|
char *memoryMap = nullptr;
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ static GLenum getGLBlendFactor(BlendFactor factor)
|
|||||||
Graphics::Graphics()
|
Graphics::Graphics()
|
||||||
: windowHasStencil(false)
|
: windowHasStencil(false)
|
||||||
, mainVAO(0)
|
, mainVAO(0)
|
||||||
|
, defaultBuffers()
|
||||||
, supportedFormats()
|
, supportedFormats()
|
||||||
{
|
{
|
||||||
gl = OpenGL();
|
gl = OpenGL();
|
||||||
@@ -243,6 +244,27 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
|
|||||||
batchedDrawState.indexBuffer = CreateStreamBuffer(BUFFERTYPE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
batchedDrawState.indexBuffer = CreateStreamBuffer(BUFFERTYPE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (capabilities.features[FEATURE_TEXEL_BUFFER] && defaultBuffers[BUFFERTYPE_TEXEL].get() == nullptr)
|
||||||
|
{
|
||||||
|
Buffer::Settings settings(Buffer::TYPEFLAG_TEXEL, 0, BUFFERUSAGE_STATIC);
|
||||||
|
std::vector<Buffer::DataDeclaration> format = {{"", DATAFORMAT_FLOAT_VEC4, 0}};
|
||||||
|
|
||||||
|
const float texel[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
|
||||||
|
love::graphics::Buffer *buffer = newBuffer(settings, format, texel, sizeof(texel), 1);
|
||||||
|
defaultBuffers[BUFFERTYPE_TEXEL].set(buffer, Acquire::NORETAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load default resources before other Volatile.
|
||||||
|
for (int i = 0; i < BUFFERTYPE_MAX_ENUM; i++)
|
||||||
|
{
|
||||||
|
if (defaultBuffers[i].get())
|
||||||
|
((Buffer *) defaultBuffers[i].get())->loadVolatile();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (defaultBuffers[BUFFERTYPE_TEXEL].get())
|
||||||
|
gl.setDefaultTexelBuffer((GLuint) defaultBuffers[BUFFERTYPE_TEXEL]->getTexelBufferHandle());
|
||||||
|
|
||||||
// Reload all volatile objects.
|
// Reload all volatile objects.
|
||||||
if (!Volatile::loadAll())
|
if (!Volatile::loadAll())
|
||||||
::printf("Could not reload all volatile objects.\n");
|
::printf("Could not reload all volatile objects.\n");
|
||||||
@@ -1366,17 +1388,19 @@ void Graphics::initCapabilities()
|
|||||||
capabilities.features[FEATURE_GLSL3] = GLAD_ES_VERSION_3_0 || gl.isCoreProfile();
|
capabilities.features[FEATURE_GLSL3] = GLAD_ES_VERSION_3_0 || gl.isCoreProfile();
|
||||||
capabilities.features[FEATURE_GLSL4] = GLAD_ES_VERSION_3_1 || (gl.isCoreProfile() && GLAD_VERSION_4_3);
|
capabilities.features[FEATURE_GLSL4] = GLAD_ES_VERSION_3_1 || (gl.isCoreProfile() && GLAD_VERSION_4_3);
|
||||||
capabilities.features[FEATURE_INSTANCING] = gl.isInstancingSupported();
|
capabilities.features[FEATURE_INSTANCING] = gl.isInstancingSupported();
|
||||||
static_assert(FEATURE_MAX_ENUM == 10, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
|
capabilities.features[FEATURE_TEXEL_BUFFER] = gl.areTexelBuffersSupported();
|
||||||
|
static_assert(FEATURE_MAX_ENUM == 11, "Graphics::initCapabilities must be updated when adding a new graphics feature!");
|
||||||
|
|
||||||
capabilities.limits[LIMIT_POINT_SIZE] = gl.getMaxPointSize();
|
capabilities.limits[LIMIT_POINT_SIZE] = gl.getMaxPointSize();
|
||||||
capabilities.limits[LIMIT_TEXTURE_SIZE] = gl.getMax2DTextureSize();
|
capabilities.limits[LIMIT_TEXTURE_SIZE] = gl.getMax2DTextureSize();
|
||||||
capabilities.limits[LIMIT_TEXTURE_LAYERS] = gl.getMaxTextureLayers();
|
capabilities.limits[LIMIT_TEXTURE_LAYERS] = gl.getMaxTextureLayers();
|
||||||
capabilities.limits[LIMIT_VOLUME_TEXTURE_SIZE] = gl.getMax3DTextureSize();
|
capabilities.limits[LIMIT_VOLUME_TEXTURE_SIZE] = gl.getMax3DTextureSize();
|
||||||
capabilities.limits[LIMIT_CUBE_TEXTURE_SIZE] = gl.getMaxCubeTextureSize();
|
capabilities.limits[LIMIT_CUBE_TEXTURE_SIZE] = gl.getMaxCubeTextureSize();
|
||||||
|
capabilities.limits[LIMIT_TEXEL_BUFFER_SIZE] = gl.getMaxTexelBufferSize();
|
||||||
capabilities.limits[LIMIT_RENDER_TARGETS] = gl.getMaxRenderTargets();
|
capabilities.limits[LIMIT_RENDER_TARGETS] = gl.getMaxRenderTargets();
|
||||||
capabilities.limits[LIMIT_TEXTURE_MSAA] = gl.getMaxSamples();
|
capabilities.limits[LIMIT_TEXTURE_MSAA] = gl.getMaxSamples();
|
||||||
capabilities.limits[LIMIT_ANISOTROPY] = gl.getMaxAnisotropy();
|
capabilities.limits[LIMIT_ANISOTROPY] = gl.getMaxAnisotropy();
|
||||||
static_assert(LIMIT_MAX_ENUM == 8, "Graphics::initCapabilities must be updated when adding a new system limit!");
|
static_assert(LIMIT_MAX_ENUM == 9, "Graphics::initCapabilities must be updated when adding a new system limit!");
|
||||||
|
|
||||||
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
|
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
|
||||||
capabilities.textureTypes[i] = gl.isTextureTypeSupported((TextureType) i);
|
capabilities.textureTypes[i] = gl.isTextureTypeSupported((TextureType) i);
|
||||||
|
|||||||
@@ -147,6 +147,9 @@ private:
|
|||||||
bool windowHasStencil;
|
bool windowHasStencil;
|
||||||
GLuint mainVAO;
|
GLuint mainVAO;
|
||||||
|
|
||||||
|
// Only needed for buffer types that can be bound to shaders.
|
||||||
|
StrongRef<love::graphics::Buffer> defaultBuffers[BUFFERTYPE_MAX_ENUM];
|
||||||
|
|
||||||
// [rendertarget][readable][srgb]
|
// [rendertarget][readable][srgb]
|
||||||
OptionalBool supportedFormats[PIXELFORMAT_MAX_ENUM][2][2][2];
|
OptionalBool supportedFormats[PIXELFORMAT_MAX_ENUM][2][2][2];
|
||||||
|
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ void OpenGL::setupContext()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize multiple texture unit support for shaders.
|
// Initialize multiple texture unit support for shaders.
|
||||||
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
|
for (int i = 0; i < TEXTURE_MAX_ENUM + 1; i++)
|
||||||
{
|
{
|
||||||
state.boundTextures[i].clear();
|
state.boundTextures[i].clear();
|
||||||
state.boundTextures[i].resize(maxTextureUnits, 0);
|
state.boundTextures[i].resize(maxTextureUnits, 0);
|
||||||
@@ -280,6 +280,10 @@ void OpenGL::deInitContext()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state.defaultTexelBuffer != 0)
|
||||||
|
gl.deleteTexture(state.defaultTexelBuffer);
|
||||||
|
state.defaultTexelBuffer = 0;
|
||||||
|
|
||||||
contextInitialized = false;
|
contextInitialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +463,11 @@ void OpenGL::initMaxValues()
|
|||||||
else
|
else
|
||||||
maxTextureArrayLayers = 0;
|
maxTextureArrayLayers = 0;
|
||||||
|
|
||||||
|
if (areTexelBuffersSupported())
|
||||||
|
glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTexelBufferSize);
|
||||||
|
else
|
||||||
|
maxTexelBufferSize = 0;
|
||||||
|
|
||||||
int maxattachments = 1;
|
int maxattachments = 1;
|
||||||
int maxdrawbuffers = 1;
|
int maxdrawbuffers = 1;
|
||||||
|
|
||||||
@@ -578,6 +587,7 @@ GLenum OpenGL::getGLBufferType(BufferType type)
|
|||||||
{
|
{
|
||||||
case BUFFERTYPE_VERTEX: return GL_ARRAY_BUFFER;
|
case BUFFERTYPE_VERTEX: return GL_ARRAY_BUFFER;
|
||||||
case BUFFERTYPE_INDEX: return GL_ELEMENT_ARRAY_BUFFER;
|
case BUFFERTYPE_INDEX: return GL_ELEMENT_ARRAY_BUFFER;
|
||||||
|
case BUFFERTYPE_TEXEL: return GL_TEXTURE_BUFFER;
|
||||||
case BUFFERTYPE_MAX_ENUM: return GL_ZERO;
|
case BUFFERTYPE_MAX_ENUM: return GL_ZERO;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,7 +602,7 @@ GLenum OpenGL::getGLTextureType(TextureType type)
|
|||||||
case TEXTURE_VOLUME: return GL_TEXTURE_3D;
|
case TEXTURE_VOLUME: return GL_TEXTURE_3D;
|
||||||
case TEXTURE_2D_ARRAY: return GL_TEXTURE_2D_ARRAY;
|
case TEXTURE_2D_ARRAY: return GL_TEXTURE_2D_ARRAY;
|
||||||
case TEXTURE_CUBE: return GL_TEXTURE_CUBE_MAP;
|
case TEXTURE_CUBE: return GL_TEXTURE_CUBE_MAP;
|
||||||
case TEXTURE_MAX_ENUM: return GL_ZERO;
|
case TEXTURE_MAX_ENUM: return GL_TEXTURE_BUFFER; // Hack
|
||||||
}
|
}
|
||||||
|
|
||||||
return GL_ZERO;
|
return GL_ZERO;
|
||||||
@@ -1084,6 +1094,11 @@ void OpenGL::bindTextureToUnit(TextureType target, GLuint texture, int textureun
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OpenGL::bindBufferTextureToUnit(GLuint texture, int textureunit, bool restoreprev, bool bindforedit)
|
||||||
|
{
|
||||||
|
bindTextureToUnit(TEXTURE_MAX_ENUM, texture, textureunit, restoreprev, bindforedit);
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGL::bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev, bool bindforedit)
|
void OpenGL::bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev, bool bindforedit)
|
||||||
{
|
{
|
||||||
TextureType textype = TEXTURE_2D;
|
TextureType textype = TEXTURE_2D;
|
||||||
@@ -1113,7 +1128,7 @@ void OpenGL::deleteTexture(GLuint texture)
|
|||||||
{
|
{
|
||||||
// glDeleteTextures binds texture 0 to all texture units the deleted texture
|
// glDeleteTextures binds texture 0 to all texture units the deleted texture
|
||||||
// was bound to before deletion.
|
// was bound to before deletion.
|
||||||
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
|
for (int i = 0; i < TEXTURE_MAX_ENUM + 1; i++)
|
||||||
{
|
{
|
||||||
for (GLuint &texid : state.boundTextures[i])
|
for (GLuint &texid : state.boundTextures[i])
|
||||||
{
|
{
|
||||||
@@ -1402,6 +1417,12 @@ bool OpenGL::isMultiFormatMRTSupported() const
|
|||||||
return getMaxRenderTargets() > 1 && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object);
|
return getMaxRenderTargets() > 1 && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool OpenGL::areTexelBuffersSupported() const
|
||||||
|
{
|
||||||
|
// Not supported in ES until 3.2, which we don't support shaders for...
|
||||||
|
return GLAD_VERSION_3_1;
|
||||||
|
}
|
||||||
|
|
||||||
int OpenGL::getMax2DTextureSize() const
|
int OpenGL::getMax2DTextureSize() const
|
||||||
{
|
{
|
||||||
return std::max(max2DTextureSize, 1);
|
return std::max(max2DTextureSize, 1);
|
||||||
@@ -1422,6 +1443,11 @@ int OpenGL::getMaxTextureLayers() const
|
|||||||
return std::max(maxTextureArrayLayers, 1);
|
return std::max(maxTextureArrayLayers, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int OpenGL::getMaxTexelBufferSize() const
|
||||||
|
{
|
||||||
|
return maxTexelBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
int OpenGL::getMaxRenderTargets() const
|
int OpenGL::getMaxRenderTargets() const
|
||||||
{
|
{
|
||||||
return std::min(maxRenderTargets, MAX_COLOR_RENDER_TARGETS);
|
return std::min(maxRenderTargets, MAX_COLOR_RENDER_TARGETS);
|
||||||
|
|||||||
@@ -306,6 +306,12 @@ public:
|
|||||||
**/
|
**/
|
||||||
GLuint getDefaultTexture(TextureType type) const;
|
GLuint getDefaultTexture(TextureType type) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the texture ID for love's default texel buffer.
|
||||||
|
**/
|
||||||
|
GLuint getDefaultTexelBuffer() const { return state.defaultTexelBuffer; }
|
||||||
|
void setDefaultTexelBuffer(GLuint tex) { state.defaultTexelBuffer = tex; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for setting the active texture unit.
|
* Helper for setting the active texture unit.
|
||||||
*
|
*
|
||||||
@@ -323,6 +329,8 @@ public:
|
|||||||
void bindTextureToUnit(TextureType target, GLuint texture, int textureunit, bool restoreprev, bool bindforedit = true);
|
void bindTextureToUnit(TextureType target, GLuint texture, int textureunit, bool restoreprev, bool bindforedit = true);
|
||||||
void bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev, bool bindforedit = true);
|
void bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev, bool bindforedit = true);
|
||||||
|
|
||||||
|
void bindBufferTextureToUnit(GLuint texture, int textureunit, bool restoreprev, bool bindforedit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for deleting an OpenGL texture.
|
* Helper for deleting an OpenGL texture.
|
||||||
* Cleans up if the texture is currently bound.
|
* Cleans up if the texture is currently bound.
|
||||||
@@ -349,6 +357,7 @@ public:
|
|||||||
bool isSamplerLODBiasSupported() const;
|
bool isSamplerLODBiasSupported() const;
|
||||||
bool isBaseVertexSupported() const;
|
bool isBaseVertexSupported() const;
|
||||||
bool isMultiFormatMRTSupported() const;
|
bool isMultiFormatMRTSupported() const;
|
||||||
|
bool areTexelBuffersSupported() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the maximum supported width or height of a texture.
|
* Returns the maximum supported width or height of a texture.
|
||||||
@@ -358,6 +367,11 @@ public:
|
|||||||
int getMaxCubeTextureSize() const;
|
int getMaxCubeTextureSize() const;
|
||||||
int getMaxTextureLayers() const;
|
int getMaxTextureLayers() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the maximum number of values in a texel buffer.
|
||||||
|
**/
|
||||||
|
int getMaxTexelBufferSize() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the maximum supported number of simultaneous render targets.
|
* Returns the maximum supported number of simultaneous render targets.
|
||||||
**/
|
**/
|
||||||
@@ -436,6 +450,7 @@ private:
|
|||||||
int max3DTextureSize;
|
int max3DTextureSize;
|
||||||
int maxCubeTextureSize;
|
int maxCubeTextureSize;
|
||||||
int maxTextureArrayLayers;
|
int maxTextureArrayLayers;
|
||||||
|
int maxTexelBufferSize;
|
||||||
int maxRenderTargets;
|
int maxRenderTargets;
|
||||||
int maxSamples;
|
int maxSamples;
|
||||||
int maxTextureUnits;
|
int maxTextureUnits;
|
||||||
@@ -451,7 +466,7 @@ private:
|
|||||||
GLuint boundBuffers[BUFFERTYPE_MAX_ENUM];
|
GLuint boundBuffers[BUFFERTYPE_MAX_ENUM];
|
||||||
|
|
||||||
// Texture unit state (currently bound texture for each texture unit.)
|
// Texture unit state (currently bound texture for each texture unit.)
|
||||||
std::vector<GLuint> boundTextures[TEXTURE_MAX_ENUM];
|
std::vector<GLuint> boundTextures[TEXTURE_MAX_ENUM + 1];
|
||||||
|
|
||||||
bool enableState[ENABLE_MAX_ENUM];
|
bool enableState[ENABLE_MAX_ENUM];
|
||||||
|
|
||||||
@@ -472,6 +487,7 @@ private:
|
|||||||
GLuint boundFramebuffers[2];
|
GLuint boundFramebuffers[2];
|
||||||
|
|
||||||
GLuint defaultTexture[TEXTURE_MAX_ENUM];
|
GLuint defaultTexture[TEXTURE_MAX_ENUM];
|
||||||
|
GLuint defaultTexelBuffer;
|
||||||
|
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,16 @@ Shader::~Shader()
|
|||||||
|
|
||||||
delete[] p.second.textures;
|
delete[] p.second.textures;
|
||||||
}
|
}
|
||||||
|
else if (p.second.baseType == UNIFORM_TEXELBUFFER)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < p.second.count; i++)
|
||||||
|
{
|
||||||
|
if (p.second.buffers[i] != nullptr)
|
||||||
|
p.second.buffers[i]->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] p.second.buffers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,6 +117,7 @@ void Shader::mapActiveUniforms()
|
|||||||
u.location = glGetUniformLocation(program, u.name.c_str());
|
u.location = glGetUniformLocation(program, u.name.c_str());
|
||||||
u.baseType = getUniformBaseType(gltype);
|
u.baseType = getUniformBaseType(gltype);
|
||||||
u.textureType = getUniformTextureType(gltype);
|
u.textureType = getUniformTextureType(gltype);
|
||||||
|
u.texelBufferType = getUniformTexelBufferType(gltype);
|
||||||
u.isDepthSampler = isDepthTextureType(gltype);
|
u.isDepthSampler = isDepthTextureType(gltype);
|
||||||
|
|
||||||
if (u.baseType == UNIFORM_MATRIX)
|
if (u.baseType == UNIFORM_MATRIX)
|
||||||
@@ -130,12 +141,22 @@ void Shader::mapActiveUniforms()
|
|||||||
if (u.location == -1)
|
if (u.location == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (u.baseType == UNIFORM_SAMPLER && builtin != BUILTIN_TEXTURE_MAIN)
|
if ((u.baseType == UNIFORM_SAMPLER && builtin != BUILTIN_TEXTURE_MAIN) || u.baseType == UNIFORM_TEXELBUFFER)
|
||||||
{
|
{
|
||||||
TextureUnit unit;
|
TextureUnit unit;
|
||||||
unit.type = u.textureType;
|
unit.type = u.textureType;
|
||||||
unit.active = true;
|
unit.active = true;
|
||||||
unit.texture = gl.getDefaultTexture(u.textureType);
|
|
||||||
|
if (u.baseType == UNIFORM_TEXELBUFFER)
|
||||||
|
{
|
||||||
|
unit.isTexelBuffer = true;
|
||||||
|
unit.texture = gl.getDefaultTexelBuffer();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unit.isTexelBuffer = false;
|
||||||
|
unit.texture = gl.getDefaultTexture(u.textureType);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < u.count; i++)
|
for (int i = 0; i < u.count; i++)
|
||||||
textureUnits.push_back(unit);
|
textureUnits.push_back(unit);
|
||||||
@@ -165,6 +186,7 @@ void Shader::mapActiveUniforms()
|
|||||||
case UNIFORM_INT:
|
case UNIFORM_INT:
|
||||||
case UNIFORM_BOOL:
|
case UNIFORM_BOOL:
|
||||||
case UNIFORM_SAMPLER:
|
case UNIFORM_SAMPLER:
|
||||||
|
case UNIFORM_TEXELBUFFER:
|
||||||
u.dataSize = sizeof(int) * u.components * u.count;
|
u.dataSize = sizeof(int) * u.components * u.count;
|
||||||
u.data = malloc(u.dataSize);
|
u.data = malloc(u.dataSize);
|
||||||
break;
|
break;
|
||||||
@@ -184,7 +206,7 @@ void Shader::mapActiveUniforms()
|
|||||||
{
|
{
|
||||||
memset(u.data, 0, u.dataSize);
|
memset(u.data, 0, u.dataSize);
|
||||||
|
|
||||||
if (u.baseType == UNIFORM_SAMPLER)
|
if (u.baseType == UNIFORM_SAMPLER || u.baseType == UNIFORM_TEXELBUFFER)
|
||||||
{
|
{
|
||||||
int startunit = (int) textureUnits.size() - u.count;
|
int startunit = (int) textureUnits.size() - u.count;
|
||||||
|
|
||||||
@@ -196,8 +218,16 @@ void Shader::mapActiveUniforms()
|
|||||||
|
|
||||||
glUniform1iv(u.location, u.count, u.ints);
|
glUniform1iv(u.location, u.count, u.ints);
|
||||||
|
|
||||||
u.textures = new love::graphics::Texture*[u.count];
|
if (u.baseType == UNIFORM_TEXELBUFFER)
|
||||||
memset(u.textures, 0, sizeof(Texture *) * u.count);
|
{
|
||||||
|
u.buffers = new love::graphics::Buffer*[u.count];
|
||||||
|
memset(u.buffers, 0, sizeof(Buffer *) * u.count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
u.textures = new love::graphics::Texture*[u.count];
|
||||||
|
memset(u.textures, 0, sizeof(Texture *) * u.count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,7 +288,6 @@ void Shader::mapActiveUniforms()
|
|||||||
{
|
{
|
||||||
if (u.textures[i] == nullptr)
|
if (u.textures[i] == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Volatile *v = dynamic_cast<Volatile *>(u.textures[i]);
|
Volatile *v = dynamic_cast<Volatile *>(u.textures[i]);
|
||||||
if (v != nullptr)
|
if (v != nullptr)
|
||||||
v->loadVolatile();
|
v->loadVolatile();
|
||||||
@@ -266,6 +295,19 @@ void Shader::mapActiveUniforms()
|
|||||||
|
|
||||||
sendTextures(&u, u.textures, u.count, true);
|
sendTextures(&u, u.textures, u.count, true);
|
||||||
}
|
}
|
||||||
|
else if (u.baseType == UNIFORM_TEXELBUFFER)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < u.count; i++)
|
||||||
|
{
|
||||||
|
if (u.buffers[i] == nullptr)
|
||||||
|
continue;
|
||||||
|
Volatile *v = dynamic_cast<Volatile *>(u.buffers[i]);
|
||||||
|
if (v != nullptr)
|
||||||
|
v->loadVolatile();
|
||||||
|
}
|
||||||
|
|
||||||
|
sendBuffers(&u, u.buffers, u.count, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure uniforms that existed before but don't exist anymore are
|
// Make sure uniforms that existed before but don't exist anymore are
|
||||||
@@ -276,16 +318,26 @@ void Shader::mapActiveUniforms()
|
|||||||
{
|
{
|
||||||
free(p.second.data);
|
free(p.second.data);
|
||||||
|
|
||||||
if (p.second.baseType != UNIFORM_SAMPLER)
|
if (p.second.baseType == UNIFORM_SAMPLER)
|
||||||
continue;
|
|
||||||
|
|
||||||
for (int i = 0; i < p.second.count; i++)
|
|
||||||
{
|
{
|
||||||
if (p.second.textures[i] != nullptr)
|
for (int i = 0; i < p.second.count; i++)
|
||||||
p.second.textures[i]->release();
|
{
|
||||||
}
|
if (p.second.textures[i] != nullptr)
|
||||||
|
p.second.textures[i]->release();
|
||||||
|
}
|
||||||
|
|
||||||
delete[] p.second.textures;
|
delete[] p.second.textures;
|
||||||
|
}
|
||||||
|
else if (p.second.baseType == UNIFORM_TEXELBUFFER)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < p.second.count; i++)
|
||||||
|
{
|
||||||
|
if (p.second.buffers[i] != nullptr)
|
||||||
|
p.second.buffers[i]->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] p.second.buffers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,7 +492,12 @@ void Shader::attach()
|
|||||||
{
|
{
|
||||||
const TextureUnit &unit = textureUnits[i];
|
const TextureUnit &unit = textureUnits[i];
|
||||||
if (unit.active)
|
if (unit.active)
|
||||||
gl.bindTextureToUnit(unit.type, unit.texture, i, false, false);
|
{
|
||||||
|
if (unit.isTexelBuffer)
|
||||||
|
gl.bindBufferTextureToUnit(unit.texture, i, false, false);
|
||||||
|
else
|
||||||
|
gl.bindTextureToUnit(unit.type, unit.texture, i, false, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// send any pending uniforms to the shader program.
|
// send any pending uniforms to the shader program.
|
||||||
@@ -503,7 +560,7 @@ void Shader::updateUniform(const UniformInfo *info, int count, bool internalupda
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (type == UNIFORM_INT || type == UNIFORM_BOOL || type == UNIFORM_SAMPLER)
|
else if (type == UNIFORM_INT || type == UNIFORM_BOOL || type == UNIFORM_SAMPLER || type == UNIFORM_TEXELBUFFER)
|
||||||
{
|
{
|
||||||
switch (info->components)
|
switch (info->components)
|
||||||
{
|
{
|
||||||
@@ -644,6 +701,109 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count)
|
||||||
|
{
|
||||||
|
Shader::sendBuffers(info, buffers, count, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isTexelBufferTypeCompatible(DataBaseType a, DataBaseType b)
|
||||||
|
{
|
||||||
|
if (a == DATA_BASETYPE_FLOAT || a == DATA_BASETYPE_UNORM || a == DATA_BASETYPE_SNORM)
|
||||||
|
return b == DATA_BASETYPE_FLOAT || b == DATA_BASETYPE_UNORM || b == DATA_BASETYPE_SNORM;
|
||||||
|
|
||||||
|
if (a == DATA_BASETYPE_INT && b == DATA_BASETYPE_INT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (a == DATA_BASETYPE_UINT && b == DATA_BASETYPE_UINT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count, bool internalUpdate)
|
||||||
|
{
|
||||||
|
if (info->baseType != UNIFORM_TEXELBUFFER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint32 requiredtypeflags = Buffer::TYPEFLAG_TEXEL;
|
||||||
|
|
||||||
|
bool shaderactive = current == this;
|
||||||
|
|
||||||
|
if (!internalUpdate && shaderactive)
|
||||||
|
flushBatchedDraws();
|
||||||
|
|
||||||
|
count = std::min(count, info->count);
|
||||||
|
|
||||||
|
// Bind the textures to the texture units.
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
love::graphics::Buffer *buffer = buffers[i];
|
||||||
|
|
||||||
|
if (buffer != nullptr)
|
||||||
|
{
|
||||||
|
if ((buffer->getTypeFlags() & requiredtypeflags) == 0)
|
||||||
|
{
|
||||||
|
if (internalUpdate)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
throw love::Exception("Shader uniform '%s' is a texel buffer, but the given Buffer was not created with texel buffer capabilities.", info->name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
DataBaseType basetype = buffer->getDataMember(0).info.baseType;
|
||||||
|
if (!isTexelBufferTypeCompatible(basetype, info->texelBufferType))
|
||||||
|
{
|
||||||
|
if (internalUpdate)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
throw love::Exception("Texel buffer's data format base type must match the variable declared in the shader.");
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->retain();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool addbuffertoarray = true;
|
||||||
|
|
||||||
|
if (info->buffers[i] != nullptr)
|
||||||
|
{
|
||||||
|
Buffer *oldbuffer = info->buffers[i];
|
||||||
|
auto it = std::find(buffersToUnmap.begin(), buffersToUnmap.end(), oldbuffer);
|
||||||
|
if (it != buffersToUnmap.end())
|
||||||
|
{
|
||||||
|
addbuffertoarray = false;
|
||||||
|
if (buffer != nullptr)
|
||||||
|
*it = buffer;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto last = buffersToUnmap.end() - 1;
|
||||||
|
*it = *last;
|
||||||
|
buffersToUnmap.erase(last);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
oldbuffer->release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addbuffertoarray && buffer != nullptr)
|
||||||
|
buffersToUnmap.push_back(buffer);
|
||||||
|
|
||||||
|
info->buffers[i] = buffer;
|
||||||
|
|
||||||
|
GLuint gltex = 0;
|
||||||
|
if (buffers[i] != nullptr)
|
||||||
|
gltex = (GLuint) buffer->getTexelBufferHandle();
|
||||||
|
else
|
||||||
|
gltex = gl.getDefaultTexelBuffer();
|
||||||
|
|
||||||
|
int texunit = info->ints[i];
|
||||||
|
|
||||||
|
if (shaderactive)
|
||||||
|
gl.bindBufferTextureToUnit(gltex, texunit, false, false);
|
||||||
|
|
||||||
|
// Store texture id so it can be re-bound to the texture unit later.
|
||||||
|
textureUnits[texunit].texture = gltex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Shader::flushBatchedDraws() const
|
void Shader::flushBatchedDraws() const
|
||||||
{
|
{
|
||||||
if (current == this)
|
if (current == this)
|
||||||
@@ -756,11 +916,20 @@ void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW,
|
|||||||
GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW];
|
GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW];
|
||||||
if (location >= 0)
|
if (location >= 0)
|
||||||
glUniform4fv(location, 13, (const GLfloat *) &data);
|
glUniform4fv(location, 13, (const GLfloat *) &data);
|
||||||
|
|
||||||
|
// TODO: Find a better place to put this.
|
||||||
|
// Buffers used in this shader can be mapped by external code without
|
||||||
|
// unmapping. We need to make sure the data on the GPU is up to date,
|
||||||
|
// otherwise the shader can read from old data.
|
||||||
|
for (Buffer *buffer : buffersToUnmap)
|
||||||
|
buffer->unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
int Shader::getUniformTypeComponents(GLenum type) const
|
int Shader::getUniformTypeComponents(GLenum type) const
|
||||||
{
|
{
|
||||||
if (getUniformBaseType(type) == UNIFORM_SAMPLER)
|
UniformType basetype = getUniformBaseType(type);
|
||||||
|
|
||||||
|
if (basetype == UNIFORM_SAMPLER || basetype == UNIFORM_TEXELBUFFER)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
@@ -889,6 +1058,10 @@ Shader::UniformType Shader::getUniformBaseType(GLenum type) const
|
|||||||
case GL_SAMPLER_CUBE_MAP_ARRAY:
|
case GL_SAMPLER_CUBE_MAP_ARRAY:
|
||||||
case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
|
case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
|
||||||
return UNIFORM_SAMPLER;
|
return UNIFORM_SAMPLER;
|
||||||
|
case GL_SAMPLER_BUFFER:
|
||||||
|
case GL_INT_SAMPLER_BUFFER:
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
|
||||||
|
return UNIFORM_TEXELBUFFER;
|
||||||
default:
|
default:
|
||||||
return UNIFORM_UNKNOWN;
|
return UNIFORM_UNKNOWN;
|
||||||
}
|
}
|
||||||
@@ -932,6 +1105,21 @@ TextureType Shader::getUniformTextureType(GLenum type) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataBaseType Shader::getUniformTexelBufferType(GLenum type) const
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case GL_SAMPLER_BUFFER:
|
||||||
|
return DATA_BASETYPE_FLOAT;
|
||||||
|
case GL_INT_SAMPLER_BUFFER:
|
||||||
|
return DATA_BASETYPE_INT;
|
||||||
|
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
|
||||||
|
return DATA_BASETYPE_UINT;
|
||||||
|
default:
|
||||||
|
return DATA_BASETYPE_MAX_ENUM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Shader::isDepthTextureType(GLenum type) const
|
bool Shader::isDepthTextureType(GLenum type) const
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ public:
|
|||||||
const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override;
|
const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override;
|
||||||
void updateUniform(const UniformInfo *info, int count) override;
|
void updateUniform(const UniformInfo *info, int count) override;
|
||||||
void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override;
|
void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override;
|
||||||
|
void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override;
|
||||||
bool hasUniform(const std::string &name) const override;
|
bool hasUniform(const std::string &name) const override;
|
||||||
ptrdiff_t getHandle() const override;
|
ptrdiff_t getHandle() const override;
|
||||||
void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override;
|
void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override;
|
||||||
@@ -75,6 +76,7 @@ private:
|
|||||||
{
|
{
|
||||||
GLuint texture = 0;
|
GLuint texture = 0;
|
||||||
TextureType type = TEXTURE_2D;
|
TextureType type = TEXTURE_2D;
|
||||||
|
bool isTexelBuffer = false;
|
||||||
bool active = false;
|
bool active = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -83,11 +85,13 @@ private:
|
|||||||
|
|
||||||
void updateUniform(const UniformInfo *info, int count, bool internalupdate);
|
void updateUniform(const UniformInfo *info, int count, bool internalupdate);
|
||||||
void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count, bool internalupdate);
|
void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count, bool internalupdate);
|
||||||
|
void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count, bool internalupdate);
|
||||||
|
|
||||||
int getUniformTypeComponents(GLenum type) const;
|
int getUniformTypeComponents(GLenum type) const;
|
||||||
MatrixSize getMatrixSize(GLenum type) const;
|
MatrixSize getMatrixSize(GLenum type) const;
|
||||||
UniformType getUniformBaseType(GLenum type) const;
|
UniformType getUniformBaseType(GLenum type) const;
|
||||||
TextureType getUniformTextureType(GLenum type) const;
|
TextureType getUniformTextureType(GLenum type) const;
|
||||||
|
DataBaseType getUniformTexelBufferType(GLenum type) const;
|
||||||
bool isDepthTextureType(GLenum type) const;
|
bool isDepthTextureType(GLenum type) const;
|
||||||
|
|
||||||
void flushBatchedDraws() const;
|
void flushBatchedDraws() const;
|
||||||
@@ -115,6 +119,8 @@ private:
|
|||||||
|
|
||||||
std::vector<std::pair<const UniformInfo *, int>> pendingUniformUpdates;
|
std::vector<std::pair<const UniformInfo *, int>> pendingUniformUpdates;
|
||||||
|
|
||||||
|
std::vector<Buffer *> buffersToUnmap;
|
||||||
|
|
||||||
float lastPointSize;
|
float lastPointSize;
|
||||||
|
|
||||||
}; // Shader
|
}; // Shader
|
||||||
|
|||||||
@@ -341,6 +341,7 @@ STRINGMAP_BEGIN(BufferType, BUFFERTYPE_MAX_ENUM, bufferTypeName)
|
|||||||
{
|
{
|
||||||
{ "vertex", BUFFERTYPE_VERTEX },
|
{ "vertex", BUFFERTYPE_VERTEX },
|
||||||
{ "index", BUFFERTYPE_INDEX },
|
{ "index", BUFFERTYPE_INDEX },
|
||||||
|
{ "texel", BUFFERTYPE_TEXEL },
|
||||||
}
|
}
|
||||||
STRINGMAP_END(BufferType, BUFFERTYPE_MAX_ENUM, bufferTypeName)
|
STRINGMAP_END(BufferType, BUFFERTYPE_MAX_ENUM, bufferTypeName)
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ enum BufferType
|
|||||||
{
|
{
|
||||||
BUFFERTYPE_VERTEX = 0,
|
BUFFERTYPE_VERTEX = 0,
|
||||||
BUFFERTYPE_INDEX,
|
BUFFERTYPE_INDEX,
|
||||||
|
BUFFERTYPE_TEXEL,
|
||||||
BUFFERTYPE_MAX_ENUM
|
BUFFERTYPE_MAX_ENUM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ static int w_Buffer_setElement(lua_State *L)
|
|||||||
|
|
||||||
size_t index = (size_t) (luaL_checkinteger(L, 2) - 1);
|
size_t index = (size_t) (luaL_checkinteger(L, 2) - 1);
|
||||||
if (index >= t->getArrayLength())
|
if (index >= t->getArrayLength())
|
||||||
return luaL_error(L, "Invalid Buffer element index: %ld", index);
|
return luaL_error(L, "Invalid Buffer element index: %d", (int) index + 1);
|
||||||
|
|
||||||
size_t stride = t->getArrayStride();
|
size_t stride = t->getArrayStride();
|
||||||
size_t offset = index * stride;
|
size_t offset = index * stride;
|
||||||
@@ -361,7 +361,7 @@ static int w_Buffer_getElement(lua_State *L)
|
|||||||
|
|
||||||
size_t index = (size_t) (luaL_checkinteger(L, 2) - 1);
|
size_t index = (size_t) (luaL_checkinteger(L, 2) - 1);
|
||||||
if (index >= t->getArrayLength())
|
if (index >= t->getArrayLength())
|
||||||
return luaL_error(L, "Invalid Buffer element index: %ld", index);
|
return luaL_error(L, "Invalid Buffer element index: %d", (int) index + 1);
|
||||||
|
|
||||||
size_t offset = index * t->getArrayStride();
|
size_t offset = index * t->getArrayStride();
|
||||||
const char *data = (const char *) t->map() + offset;
|
const char *data = (const char *) t->map() + offset;
|
||||||
|
|||||||
@@ -1517,6 +1517,16 @@ static void luax_optbuffersettings(lua_State *L, int idx, Buffer::Settings &sett
|
|||||||
|
|
||||||
static void luax_checkbufferformat(lua_State *L, int idx, std::vector<Buffer::DataDeclaration> &format)
|
static void luax_checkbufferformat(lua_State *L, int idx, std::vector<Buffer::DataDeclaration> &format)
|
||||||
{
|
{
|
||||||
|
if (lua_type(L, idx) == LUA_TSTRING)
|
||||||
|
{
|
||||||
|
Buffer::DataDeclaration decl("", DATAFORMAT_MAX_ENUM);
|
||||||
|
const char *formatstr = luaL_checkstring(L, idx);
|
||||||
|
if (!getConstant(formatstr, decl.format))
|
||||||
|
luax_enumerror(L, "data format", getConstants(decl.format), formatstr);
|
||||||
|
format.push_back(decl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
luaL_checktype(L, idx, LUA_TTABLE);
|
luaL_checktype(L, idx, LUA_TTABLE);
|
||||||
int tablelen = luax_objlen(L, idx);
|
int tablelen = luax_objlen(L, idx);
|
||||||
|
|
||||||
@@ -1528,16 +1538,8 @@ static void luax_checkbufferformat(lua_State *L, int idx, std::vector<Buffer::Da
|
|||||||
Buffer::DataDeclaration decl("", DATAFORMAT_MAX_ENUM);
|
Buffer::DataDeclaration decl("", DATAFORMAT_MAX_ENUM);
|
||||||
|
|
||||||
lua_getfield(L, -1, "name");
|
lua_getfield(L, -1, "name");
|
||||||
if (lua_type(L, -1) != LUA_TSTRING)
|
if (!lua_isnoneornil(L, -1))
|
||||||
{
|
decl.name = luax_checkstring(L, -1);
|
||||||
std::ostringstream ss;
|
|
||||||
ss << "'name' field expected in array element #";
|
|
||||||
ss << i;
|
|
||||||
ss << " of format table";
|
|
||||||
std::string str = ss.str();
|
|
||||||
luaL_argerror(L, idx, str.c_str());
|
|
||||||
}
|
|
||||||
decl.name = luax_checkstring(L, -1);
|
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
lua_getfield(L, -1, "format");
|
lua_getfield(L, -1, "format");
|
||||||
|
|||||||
@@ -287,6 +287,23 @@ int w_Shader_sendTextures(lua_State *L, int startidx, Shader *shader, const Shad
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int w_Shader_sendBuffers(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info)
|
||||||
|
{
|
||||||
|
int count = _getCount(L, startidx, info);
|
||||||
|
|
||||||
|
std::vector<Buffer *> buffers;
|
||||||
|
buffers.reserve(count);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
Buffer *buffer = luax_checktype<Buffer>(L, startidx + i);
|
||||||
|
buffers.push_back(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
luax_catchexcept(L, [&]() { shader->sendBuffers(info, buffers.data(), count); });
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int w_Shader_sendLuaValues(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info, const char *name)
|
static int w_Shader_sendLuaValues(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info, const char *name)
|
||||||
{
|
{
|
||||||
switch (info->baseType)
|
switch (info->baseType)
|
||||||
@@ -303,6 +320,8 @@ static int w_Shader_sendLuaValues(lua_State *L, int startidx, Shader *shader, co
|
|||||||
return w_Shader_sendBooleans(L, startidx, shader, info);
|
return w_Shader_sendBooleans(L, startidx, shader, info);
|
||||||
case Shader::UNIFORM_SAMPLER:
|
case Shader::UNIFORM_SAMPLER:
|
||||||
return w_Shader_sendTextures(L, startidx, shader, info);
|
return w_Shader_sendTextures(L, startidx, shader, info);
|
||||||
|
case Shader::UNIFORM_TEXELBUFFER:
|
||||||
|
return w_Shader_sendBuffers(L, startidx, shader, info);
|
||||||
default:
|
default:
|
||||||
return luaL_error(L, "Unknown variable type for shader uniform '%s", name);
|
return luaL_error(L, "Unknown variable type for shader uniform '%s", name);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user