mirror of
https://github.com/love2d/love.git
synced 2026-08-17 11:00:31 +02:00
Merge branch '12.0-development' into metal
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -167,14 +167,14 @@ love::graphics::Texture *Graphics::newTexture(const Texture::Settings &settings,
|
||||
return new Texture(this, settings, data);
|
||||
}
|
||||
|
||||
love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles)
|
||||
love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles)
|
||||
{
|
||||
return new ShaderStage(this, stage, source, gles, cachekey);
|
||||
}
|
||||
|
||||
love::graphics::Shader *Graphics::newShaderInternal(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel)
|
||||
love::graphics::Shader *Graphics::newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM])
|
||||
{
|
||||
return new Shader(vertex, pixel);
|
||||
return new Shader(stages);
|
||||
}
|
||||
|
||||
love::graphics::Buffer *Graphics::newBuffer(const Buffer::Settings &settings, const std::vector<Buffer::DataDeclaration> &format, const void *data, size_t size, size_t arraylength)
|
||||
@@ -358,6 +358,7 @@ bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth,
|
||||
batchedDrawState.indexBuffer = CreateStreamBuffer(BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX);
|
||||
}
|
||||
|
||||
// TODO: one buffer each for float, int, uint
|
||||
if (capabilities.features[FEATURE_TEXEL_BUFFER] && defaultBuffers[BUFFERUSAGE_TEXEL].get() == nullptr)
|
||||
{
|
||||
Buffer::Settings settings(BUFFERUSAGEFLAG_TEXEL, BUFFERDATAUSAGE_STATIC);
|
||||
@@ -378,7 +379,7 @@ bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth,
|
||||
data.resize(Buffer::SHADER_STORAGE_BUFFER_MAX_STRIDE / 4);
|
||||
|
||||
auto buffer = newBuffer(settings, format, data.data(), data.size() * sizeof(float), data.size());
|
||||
defaultBuffers[BUFFERUSAGE_TEXEL].set(buffer, Acquire::NORETAIN);
|
||||
defaultBuffers[BUFFERUSAGE_SHADER_STORAGE].set(buffer, Acquire::NORETAIN);
|
||||
}
|
||||
|
||||
// Load default resources before other Volatile.
|
||||
@@ -418,8 +419,8 @@ bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth,
|
||||
if (!Shader::standardShaders[i])
|
||||
{
|
||||
std::vector<std::string> stages;
|
||||
stages.push_back(Shader::getDefaultCode(stype, ShaderStage::STAGE_VERTEX));
|
||||
stages.push_back(Shader::getDefaultCode(stype, ShaderStage::STAGE_PIXEL));
|
||||
stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_VERTEX));
|
||||
stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_PIXEL));
|
||||
Shader::standardShaders[i] = newShader(stages);
|
||||
}
|
||||
}
|
||||
@@ -486,6 +487,88 @@ void Graphics::setActive(bool enable)
|
||||
active = enable;
|
||||
}
|
||||
|
||||
static bool computeDispatchBarriers(Shader *shader, GLbitfield &preDispatchBarriers, GLbitfield &postDispatchBarriers)
|
||||
{
|
||||
// TODO: handle indirect argument buffer types, when those are added.
|
||||
for (auto buffer : shader->getActiveWritableStorageBuffers())
|
||||
{
|
||||
if (buffer == nullptr)
|
||||
return false;
|
||||
|
||||
auto usage = buffer->getUsageFlags();
|
||||
|
||||
postDispatchBarriers |= GL_BUFFER_UPDATE_BARRIER_BIT;
|
||||
|
||||
if (usage & BUFFERUSAGEFLAG_SHADER_STORAGE)
|
||||
{
|
||||
preDispatchBarriers |= GL_SHADER_STORAGE_BARRIER_BIT;
|
||||
postDispatchBarriers |= GL_SHADER_STORAGE_BARRIER_BIT;
|
||||
}
|
||||
|
||||
if (usage & BUFFERUSAGEFLAG_TEXEL)
|
||||
postDispatchBarriers |= GL_TEXTURE_FETCH_BARRIER_BIT;
|
||||
|
||||
if (usage & BUFFERUSAGEFLAG_INDEX)
|
||||
postDispatchBarriers |= GL_ELEMENT_ARRAY_BARRIER_BIT;
|
||||
|
||||
if (usage & BUFFERUSAGEFLAG_VERTEX)
|
||||
postDispatchBarriers |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
|
||||
|
||||
if (usage & (BUFFERUSAGEFLAG_COPY_SOURCE | BUFFERUSAGEFLAG_COPY_DEST))
|
||||
postDispatchBarriers |= GL_PIXEL_BUFFER_BARRIER_BIT;
|
||||
}
|
||||
|
||||
for (const auto &binding : shader->getStorageTextureBindings())
|
||||
{
|
||||
if (binding.texture == nullptr)
|
||||
return false;
|
||||
|
||||
if (binding.access == GL_READ_ONLY)
|
||||
continue;
|
||||
|
||||
preDispatchBarriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
|
||||
|
||||
postDispatchBarriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
|
||||
| GL_TEXTURE_UPDATE_BARRIER_BIT
|
||||
| GL_TEXTURE_FETCH_BARRIER_BIT;
|
||||
|
||||
if (binding.texture->isRenderTarget())
|
||||
postDispatchBarriers |= GL_FRAMEBUFFER_BARRIER_BIT;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Graphics::dispatch(int x, int y, int z)
|
||||
{
|
||||
// Set by higher level code before calling dispatch(x, y, z).
|
||||
auto shader = (Shader *) Shader::current;
|
||||
|
||||
GLbitfield preDispatchBarriers = 0;
|
||||
GLbitfield postDispatchBarriers = 0;
|
||||
|
||||
if (!computeDispatchBarriers(shader, preDispatchBarriers, postDispatchBarriers))
|
||||
return false;
|
||||
|
||||
// glMemoryBarrier before dispatch to make sure non-compute-read ->
|
||||
// compute-write is synced.
|
||||
// TODO: is this needed? spec language around GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
|
||||
// makes me think so.
|
||||
// This is overly conservative (dispatch -> dispatch will have redundant
|
||||
// barriers).
|
||||
if (preDispatchBarriers != 0)
|
||||
glMemoryBarrier(preDispatchBarriers);
|
||||
|
||||
glDispatchCompute(x, y, z);
|
||||
|
||||
// Not as (theoretically) efficient as issuing the barrier right before
|
||||
// they're used later, but much less complicated.
|
||||
if (postDispatchBarriers != 0)
|
||||
glMemoryBarrier(postDispatchBarriers);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Graphics::draw(const DrawCommand &cmd)
|
||||
{
|
||||
gl.prepareDraw(this);
|
||||
@@ -771,7 +854,7 @@ void Graphics::endPass()
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth)
|
||||
void Graphics::clear(OptionalColorD c, OptionalInt stencil, OptionalDouble depth)
|
||||
{
|
||||
if (c.hasValue || stencil.hasValue || depth.hasValue)
|
||||
flushBatchedDraws();
|
||||
@@ -780,8 +863,9 @@ void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth
|
||||
|
||||
if (c.hasValue)
|
||||
{
|
||||
gammaCorrectColor(c.value);
|
||||
glClearColor(c.value.r, c.value.g, c.value.b, c.value.a);
|
||||
Colorf cf((float)c.value.r, (float)c.value.g, (float)c.value.b, (float)c.value.b);
|
||||
gammaCorrectColor(cf);
|
||||
glClearColor(cf.r, cf.g, cf.b, cf.a);
|
||||
flags |= GL_COLOR_BUFFER_BIT;
|
||||
}
|
||||
|
||||
@@ -817,17 +901,19 @@ void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth)
|
||||
void Graphics::clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth)
|
||||
{
|
||||
if (colors.size() == 0 && !stencil.hasValue && !depth.hasValue)
|
||||
return;
|
||||
|
||||
int ncolorRTs = (int) states.back().renderTargets.colors.size();
|
||||
const auto &rts = states.back().renderTargets.colors;
|
||||
|
||||
int ncolorRTs = (int) rts.size();
|
||||
int ncolors = (int) colors.size();
|
||||
|
||||
if (ncolors <= 1 && ncolorRTs <= 1)
|
||||
if (ncolors <= 1 && (ncolorRTs == 0 || (ncolorRTs == 1 && rts[0].texture != nullptr && !isPixelFormatInteger(rts[0].texture->getPixelFormat()))))
|
||||
{
|
||||
clear(ncolors > 0 ? colors[0] : OptionalColorf(), stencil, depth);
|
||||
clear(ncolors > 0 ? colors[0] : OptionalColorD(), stencil, depth);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -841,18 +927,39 @@ void Graphics::clear(const std::vector<OptionalColorf> &colors, OptionalInt sten
|
||||
if (!colors[i].hasValue)
|
||||
continue;
|
||||
|
||||
Colorf c = colors[i].value;
|
||||
gammaCorrectColor(c);
|
||||
PixelFormatType datatype = PIXELFORMATTYPE_UNORM;
|
||||
if (rts[i].texture != nullptr)
|
||||
datatype = getPixelFormatInfo(rts[i].texture->getPixelFormat()).dataType;
|
||||
|
||||
ColorD c = colors[i].value;
|
||||
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0)
|
||||
{
|
||||
const GLfloat carray[] = {c.r, c.g, c.b, c.a};
|
||||
glClearBufferfv(GL_COLOR, i, carray);
|
||||
if (datatype == PIXELFORMATTYPE_SINT)
|
||||
{
|
||||
const GLint carray[] = {(GLint)c.r, (GLint)c.g, (GLint)c.b, (GLint)c.a};
|
||||
glClearBufferiv(GL_COLOR, i, carray);
|
||||
}
|
||||
else if (datatype == PIXELFORMATTYPE_UINT)
|
||||
{
|
||||
const GLuint carray[] = {(GLuint)c.r, (GLuint)c.g, (GLuint)c.b, (GLuint)c.a};
|
||||
glClearBufferuiv(GL_COLOR, i, carray);
|
||||
}
|
||||
else
|
||||
{
|
||||
Colorf cf((float)c.r, (float)c.g, (float)c.b, (float)c.a);
|
||||
gammaCorrectColor(cf);
|
||||
const GLfloat carray[] = {cf.r, cf.g, cf.b, cf.a};
|
||||
glClearBufferfv(GL_COLOR, i, carray);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Colorf cf((float)c.r, (float)c.g, (float)c.b, (float)c.a);
|
||||
gammaCorrectColor(cf);
|
||||
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0 + i);
|
||||
glClearColor(c.r, c.g, c.b, c.a);
|
||||
glClearColor(cf.r, cf.g, cf.b, cf.a);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
drawbuffersmodified = true;
|
||||
@@ -1566,10 +1673,13 @@ void Graphics::initCapabilities()
|
||||
capabilities.limits[LIMIT_CUBE_TEXTURE_SIZE] = gl.getMaxCubeTextureSize();
|
||||
capabilities.limits[LIMIT_TEXEL_BUFFER_SIZE] = gl.getMaxTexelBufferSize();
|
||||
capabilities.limits[LIMIT_SHADER_STORAGE_BUFFER_SIZE] = gl.getMaxShaderStorageBufferSize();
|
||||
capabilities.limits[LIMIT_THREADGROUPS_X] = gl.getMaxComputeWorkGroupsX();
|
||||
capabilities.limits[LIMIT_THREADGROUPS_Y] = gl.getMaxComputeWorkGroupsY();
|
||||
capabilities.limits[LIMIT_THREADGROUPS_Z] = gl.getMaxComputeWorkGroupsZ();
|
||||
capabilities.limits[LIMIT_RENDER_TARGETS] = gl.getMaxRenderTargets();
|
||||
capabilities.limits[LIMIT_TEXTURE_MSAA] = gl.getMaxSamples();
|
||||
capabilities.limits[LIMIT_ANISOTROPY] = gl.getMaxAnisotropy();
|
||||
static_assert(LIMIT_MAX_ENUM == 10, "Graphics::initCapabilities must be updated when adding a new system limit!");
|
||||
static_assert(LIMIT_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new system limit!");
|
||||
|
||||
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
|
||||
capabilities.textureTypes[i] = gl.isTextureTypeSupported((TextureType) i);
|
||||
@@ -1600,7 +1710,7 @@ PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool
|
||||
}
|
||||
}
|
||||
|
||||
bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB)
|
||||
bool Graphics::isPixelFormatSupported(PixelFormat format, PixelFormatUsageFlags usage, bool sRGB)
|
||||
{
|
||||
if (sRGB && format == PIXELFORMAT_RGBA8_UNORM)
|
||||
{
|
||||
@@ -1608,22 +1718,20 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, boo
|
||||
sRGB = false;
|
||||
}
|
||||
|
||||
uint32 requiredflags = 0;
|
||||
if (rendertarget)
|
||||
requiredflags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET;
|
||||
if (readable)
|
||||
requiredflags |= PIXELFORMATUSAGEFLAGS_SAMPLE;
|
||||
bool rendertarget = (usage & PIXELFORMATUSAGEFLAGS_RENDERTARGET) != 0;
|
||||
bool readable = (usage & PIXELFORMATUSAGEFLAGS_SAMPLE) != 0;
|
||||
bool computewrite = (usage & PIXELFORMATUSAGEFLAGS_COMPUTEWRITE) != 0;
|
||||
|
||||
format = getSizedFormat(format, rendertarget, readable);
|
||||
|
||||
OptionalBool &supported = supportedFormats[format][rendertarget ? 1 : 0][readable ? 1 : 0][sRGB ? 1 : 0];
|
||||
OptionalBool &supported = supportedFormats[format][rendertarget ? 1 : 0][readable ? 1 : 0][computewrite ? 1 : 0][sRGB ? 1 : 0];
|
||||
|
||||
if (supported.hasValue)
|
||||
return supported.value;
|
||||
|
||||
auto supportedflags = OpenGL::getPixelFormatUsageFlags(format);
|
||||
uint32 supportedflags = OpenGL::getPixelFormatUsageFlags(format);
|
||||
|
||||
if ((requiredflags & supportedflags) != requiredflags)
|
||||
if ((usage & supportedflags) != usage)
|
||||
{
|
||||
supported.set(false);
|
||||
return supported.value;
|
||||
@@ -1664,7 +1772,7 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, boo
|
||||
// Make sure at least something is bound to a color attachment. I believe
|
||||
// this is required on ES2 but I'm not positive.
|
||||
if (isPixelFormatDepthStencil(format))
|
||||
gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, gl.getDefaultTexture(TEXTURE_2D), 0, 0, 0);
|
||||
gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, gl.getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT), 0, 0, 0);
|
||||
|
||||
if (readable)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -68,12 +68,14 @@ public:
|
||||
|
||||
void setActive(bool active) override;
|
||||
|
||||
bool dispatch(int x, int y, int z) override;
|
||||
|
||||
void draw(const DrawCommand &cmd) override;
|
||||
void draw(const DrawIndexedCommand &cmd) override;
|
||||
void drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, love::graphics::Texture *texture) override;
|
||||
|
||||
void clear(OptionalColorf color, OptionalInt stencil, OptionalDouble depth) override;
|
||||
void clear(const std::vector<OptionalColorf> &colors, OptionalInt stencil, OptionalDouble depth) override;
|
||||
void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override;
|
||||
void clear(const std::vector<OptionalColorD> &colors, OptionalInt stencil, OptionalDouble depth) override;
|
||||
|
||||
void discard(const std::vector<bool> &colorbuffers, bool depthstencil) override;
|
||||
|
||||
@@ -105,7 +107,7 @@ public:
|
||||
void setWireframe(bool enable) override;
|
||||
|
||||
PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override;
|
||||
bool isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB = false) override;
|
||||
bool isPixelFormatSupported(PixelFormat format, PixelFormatUsageFlags usage, bool sRGB = false) override;
|
||||
Renderer getRenderer() const override;
|
||||
bool usesGLSLES() const override;
|
||||
RendererInfo getRendererInfo() const override;
|
||||
@@ -137,8 +139,8 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
love::graphics::ShaderStage *newShaderStageInternal(ShaderStage::StageType stage, const std::string &cachekey, const std::string &source, bool gles) override;
|
||||
love::graphics::Shader *newShaderInternal(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel) override;
|
||||
love::graphics::ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) override;
|
||||
love::graphics::Shader *newShaderInternal(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM]) override;
|
||||
love::graphics::StreamBuffer *newStreamBuffer(BufferUsage type, size_t size) override;
|
||||
void setRenderTargetsInternal(const RenderTargets &rts, int w, int h, int pixelw, int pixelh, bool hasSRGBtexture) override;
|
||||
void initCapabilities() override;
|
||||
@@ -169,8 +171,8 @@ private:
|
||||
// Only needed for buffer types that can be bound to shaders.
|
||||
StrongRef<love::graphics::Buffer> defaultBuffers[BUFFERUSAGE_MAX_ENUM];
|
||||
|
||||
// [rendertarget][readable][srgb]
|
||||
OptionalBool supportedFormats[PIXELFORMAT_MAX_ENUM][2][2][2];
|
||||
// [rendertarget][readable][computewrite][srgb]
|
||||
OptionalBool supportedFormats[PIXELFORMAT_MAX_ENUM][2][2][2][2];
|
||||
|
||||
}; // Graphics
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -103,6 +103,9 @@ OpenGL::OpenGL()
|
||||
, maxTextureArrayLayers(0)
|
||||
, maxTexelBufferSize(0)
|
||||
, maxShaderStorageBufferSize(0)
|
||||
, maxComputeWorkGroupsX(0)
|
||||
, maxComputeWorkGroupsY(0)
|
||||
, maxComputeWorkGroupsZ(0)
|
||||
, maxRenderTargets(1)
|
||||
, maxSamples(1)
|
||||
, maxTextureUnits(1)
|
||||
@@ -122,6 +125,20 @@ bool OpenGL::initContext()
|
||||
if (!gladLoadGLLoader(LOVEGetProcAddress))
|
||||
return false;
|
||||
|
||||
initVendor();
|
||||
|
||||
bugs = {};
|
||||
|
||||
if (GLAD_ES_VERSION_3_0 && !GLAD_ES_VERSION_3_1)
|
||||
{
|
||||
const char *device = (const char *) glGetString(GL_RENDERER);
|
||||
if (getVendor() == VENDOR_VIVANTE && strstr(device, "Vivante GC7000UL"))
|
||||
bugs.brokenGLES3 = true;
|
||||
}
|
||||
|
||||
if (bugs.brokenGLES3)
|
||||
GLAD_ES_VERSION_3_0 = false;
|
||||
|
||||
if (GLAD_VERSION_3_2)
|
||||
{
|
||||
GLint profileMask = 0;
|
||||
@@ -132,9 +149,6 @@ bool OpenGL::initContext()
|
||||
coreProfile = false;
|
||||
|
||||
initOpenGLFunctions();
|
||||
initVendor();
|
||||
|
||||
bugs = {};
|
||||
|
||||
#if defined(LOVE_WINDOWS) || defined(LOVE_LINUX)
|
||||
// See the comments in OpenGL.h.
|
||||
@@ -278,7 +292,7 @@ void OpenGL::setupContext()
|
||||
// This can't be done in initContext with the rest of the bug checks because
|
||||
// isPixelFormatSupported relies on state initialized here / after init.
|
||||
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
|
||||
if (GLAD_ES_VERSION_3_0 && gfx != nullptr && !gfx->isPixelFormatSupported(PIXELFORMAT_R8_UNORM, true, true))
|
||||
if (GLAD_ES_VERSION_3_0 && gfx != nullptr && !gfx->isPixelFormatSupported(PIXELFORMAT_R8_UNORM, PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_RENDERTARGET))
|
||||
bugs.brokenR8PixelFormat = true;
|
||||
#endif
|
||||
}
|
||||
@@ -290,10 +304,13 @@ void OpenGL::deInitContext()
|
||||
|
||||
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
|
||||
{
|
||||
if (state.defaultTexture[i] != 0)
|
||||
for (int datatype = DATA_BASETYPE_FLOAT; datatype <= DATA_BASETYPE_UINT; datatype++)
|
||||
{
|
||||
gl.deleteTexture(state.defaultTexture[i]);
|
||||
state.defaultTexture[i] = 0;
|
||||
if (state.defaultTexture[i][datatype] != 0)
|
||||
{
|
||||
gl.deleteTexture(state.defaultTexture[i][datatype]);
|
||||
state.defaultTexture[i][datatype] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -500,6 +517,19 @@ void OpenGL::initMaxValues()
|
||||
maxShaderStorageBufferBindings = 0;
|
||||
}
|
||||
|
||||
if (GLAD_ES_VERSION_3_1 || GLAD_VERSION_4_3)
|
||||
{
|
||||
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, &maxComputeWorkGroupsX);
|
||||
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, &maxComputeWorkGroupsY);
|
||||
glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, &maxComputeWorkGroupsZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
maxComputeWorkGroupsX = 0;
|
||||
maxComputeWorkGroupsY = 0;
|
||||
maxComputeWorkGroupsZ = 0;
|
||||
}
|
||||
|
||||
int maxattachments = 1;
|
||||
int maxdrawbuffers = 1;
|
||||
|
||||
@@ -542,6 +572,7 @@ void OpenGL::createDefaultTexture()
|
||||
// which would create the need to use different "passthrough" shaders for
|
||||
// untextured primitives vs images.
|
||||
const GLubyte pix[] = {255, 255, 255, 255};
|
||||
const GLubyte intpix[] = {1, 1, 1, 1};
|
||||
|
||||
SamplerState s;
|
||||
s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST;
|
||||
@@ -549,41 +580,55 @@ void OpenGL::createDefaultTexture()
|
||||
|
||||
for (int i = 0; i < TEXTURE_MAX_ENUM; i++)
|
||||
{
|
||||
state.defaultTexture[i] = 0;
|
||||
|
||||
TextureType type = (TextureType) i;
|
||||
|
||||
if (!isTextureTypeSupported(type))
|
||||
continue;
|
||||
|
||||
GLuint curtexture = state.boundTextures[type][0];
|
||||
|
||||
glGenTextures(1, &state.defaultTexture[type]);
|
||||
bindTextureToUnit(type, state.defaultTexture[type], 0, false);
|
||||
|
||||
setSamplerState(type, s);
|
||||
|
||||
bool isSRGB = false;
|
||||
rawTexStorage(type, 1, PIXELFORMAT_RGBA8_UNORM, isSRGB, 1, 1);
|
||||
|
||||
TextureFormat fmt = convertPixelFormat(PIXELFORMAT_RGBA8_UNORM, false, isSRGB);
|
||||
|
||||
int slices = type == TEXTURE_CUBE ? 6 : 1;
|
||||
|
||||
for (int slice = 0; slice < slices; slice++)
|
||||
for (int datatype = (int)DATA_BASETYPE_FLOAT; datatype <= (int)DATA_BASETYPE_UINT; datatype++)
|
||||
{
|
||||
GLenum gltarget = getGLTextureType(type);
|
||||
state.defaultTexture[i][datatype] = 0;
|
||||
|
||||
if (type == TEXTURE_CUBE)
|
||||
gltarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
|
||||
TextureType type = (TextureType) i;
|
||||
|
||||
if (type == TEXTURE_2D || type == TEXTURE_CUBE)
|
||||
glTexSubImage2D(gltarget, 0, 0, 0, 1, 1, fmt.externalformat, fmt.type, pix);
|
||||
else if (type == TEXTURE_2D_ARRAY || type == TEXTURE_VOLUME)
|
||||
glTexSubImage3D(gltarget, 0, 0, 0, slice, 1, 1, 1, fmt.externalformat, fmt.type, pix);
|
||||
if (!isTextureTypeSupported(type))
|
||||
continue;
|
||||
|
||||
if (datatype != DATA_BASETYPE_FLOAT && !(GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0))
|
||||
continue;
|
||||
|
||||
GLuint curtexture = state.boundTextures[type][0];
|
||||
|
||||
glGenTextures(1, &state.defaultTexture[type][datatype]);
|
||||
bindTextureToUnit(type, state.defaultTexture[type][datatype], 0, false);
|
||||
|
||||
setSamplerState(type, s);
|
||||
|
||||
PixelFormat format = PIXELFORMAT_RGBA8_UNORM;
|
||||
if (datatype == DATA_BASETYPE_INT)
|
||||
format = PIXELFORMAT_RGBA8_INT;
|
||||
else if (datatype == DATA_BASETYPE_UINT)
|
||||
format = PIXELFORMAT_RGBA8_UINT;
|
||||
|
||||
const GLubyte *p = datatype == DATA_BASETYPE_FLOAT ? pix : intpix;
|
||||
|
||||
bool isSRGB = false;
|
||||
rawTexStorage(type, 1, format, isSRGB, 1, 1);
|
||||
|
||||
TextureFormat fmt = convertPixelFormat(format, false, isSRGB);
|
||||
|
||||
int slices = type == TEXTURE_CUBE ? 6 : 1;
|
||||
|
||||
for (int slice = 0; slice < slices; slice++)
|
||||
{
|
||||
GLenum gltarget = getGLTextureType(type);
|
||||
|
||||
if (type == TEXTURE_CUBE)
|
||||
gltarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice;
|
||||
|
||||
if (type == TEXTURE_2D || type == TEXTURE_CUBE)
|
||||
glTexSubImage2D(gltarget, 0, 0, 0, 1, 1, fmt.externalformat, fmt.type, p);
|
||||
else if (type == TEXTURE_2D_ARRAY || type == TEXTURE_VOLUME)
|
||||
glTexSubImage3D(gltarget, 0, 0, 0, slice, 1, 1, 1, fmt.externalformat, fmt.type, p);
|
||||
}
|
||||
|
||||
bindTextureToUnit(type, curtexture, 0, false);
|
||||
}
|
||||
|
||||
bindTextureToUnit(type, curtexture, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1086,9 +1131,9 @@ GLuint OpenGL::getDefaultFBO() const
|
||||
#endif
|
||||
}
|
||||
|
||||
GLuint OpenGL::getDefaultTexture(TextureType type) const
|
||||
GLuint OpenGL::getDefaultTexture(TextureType type, DataBaseType datatype) const
|
||||
{
|
||||
return state.defaultTexture[type];
|
||||
return state.defaultTexture[type][datatype];
|
||||
}
|
||||
|
||||
void OpenGL::setTextureUnit(int textureunit)
|
||||
@@ -1139,14 +1184,19 @@ void OpenGL::bindTextureToUnit(Texture *texture, int textureunit, bool restorepr
|
||||
}
|
||||
else
|
||||
{
|
||||
DataBaseType datatype = DATA_BASETYPE_FLOAT;
|
||||
|
||||
if (textureunit == 0 && Shader::current != nullptr)
|
||||
{
|
||||
TextureType shadertex = Shader::current->getMainTextureType();
|
||||
if (shadertex != TEXTURE_MAX_ENUM)
|
||||
textype = shadertex;
|
||||
const Shader::UniformInfo *info = Shader::current->getMainTextureInfo();
|
||||
if (info != nullptr)
|
||||
{
|
||||
textype = info->textureType;
|
||||
datatype = info->dataBaseType;
|
||||
}
|
||||
}
|
||||
|
||||
handle = getDefaultTexture(textype);
|
||||
handle = getDefaultTexture(textype, datatype);
|
||||
}
|
||||
|
||||
bindTextureToUnit(textype, handle, textureunit, restoreprev, bindforedit);
|
||||
@@ -1510,6 +1560,21 @@ int OpenGL::getMaxShaderStorageBufferSize() const
|
||||
return maxShaderStorageBufferSize;
|
||||
}
|
||||
|
||||
int OpenGL::getMaxComputeWorkGroupsX() const
|
||||
{
|
||||
return maxComputeWorkGroupsX;
|
||||
}
|
||||
|
||||
int OpenGL::getMaxComputeWorkGroupsY() const
|
||||
{
|
||||
return maxComputeWorkGroupsY;
|
||||
}
|
||||
|
||||
int OpenGL::getMaxComputeWorkGroupsZ() const
|
||||
{
|
||||
return maxComputeWorkGroupsZ;
|
||||
}
|
||||
|
||||
int OpenGL::getMaxRenderTargets() const
|
||||
{
|
||||
return std::min(maxRenderTargets, MAX_COLOR_RENDER_TARGETS);
|
||||
@@ -1620,6 +1685,7 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r
|
||||
f.externalformat = GL_RGBA;
|
||||
f.type = GL_UNSIGNED_SHORT;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_R16_FLOAT:
|
||||
f.internalformat = GL_R16F;
|
||||
f.externalformat = GL_RED;
|
||||
@@ -1660,6 +1726,97 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r
|
||||
f.type = GL_FLOAT;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_R8_INT:
|
||||
f.internalformat = GL_R8I;
|
||||
f.externalformat = GL_RED_INTEGER;
|
||||
f.type = GL_BYTE;
|
||||
break;
|
||||
case PIXELFORMAT_R8_UINT:
|
||||
f.internalformat = GL_R8UI;
|
||||
f.externalformat = GL_RED_INTEGER;
|
||||
f.type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case PIXELFORMAT_RG8_INT:
|
||||
f.internalformat = GL_RG8I;
|
||||
f.externalformat = GL_RG_INTEGER;
|
||||
f.type = GL_BYTE;
|
||||
break;
|
||||
case PIXELFORMAT_RG8_UINT:
|
||||
f.internalformat = GL_RG8UI;
|
||||
f.externalformat = GL_RG_INTEGER;
|
||||
f.type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA8_INT:
|
||||
f.internalformat = GL_RGBA8I;
|
||||
f.externalformat = GL_RGBA_INTEGER;
|
||||
f.type = GL_BYTE;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA8_UINT:
|
||||
f.internalformat = GL_RGBA8UI;
|
||||
f.externalformat = GL_RGBA_INTEGER;
|
||||
f.type = GL_UNSIGNED_BYTE;
|
||||
break;
|
||||
case PIXELFORMAT_R16_INT:
|
||||
f.internalformat = GL_R16I;
|
||||
f.externalformat = GL_RED_INTEGER;
|
||||
f.type = GL_SHORT;
|
||||
break;
|
||||
case PIXELFORMAT_R16_UINT:
|
||||
f.internalformat = GL_R16UI;
|
||||
f.externalformat = GL_RED_INTEGER;
|
||||
f.type = GL_UNSIGNED_SHORT;
|
||||
break;
|
||||
case PIXELFORMAT_RG16_INT:
|
||||
f.internalformat = GL_RG16I;
|
||||
f.externalformat = GL_RG_INTEGER;
|
||||
f.type = GL_SHORT;
|
||||
break;
|
||||
case PIXELFORMAT_RG16_UINT:
|
||||
f.internalformat = GL_RG16UI;
|
||||
f.externalformat = GL_RG_INTEGER;
|
||||
f.type = GL_UNSIGNED_SHORT;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA16_INT:
|
||||
f.internalformat = GL_RGBA16I;
|
||||
f.externalformat = GL_RGBA_INTEGER;
|
||||
f.type = GL_SHORT;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA16_UINT:
|
||||
f.internalformat = GL_RGBA16UI;
|
||||
f.externalformat = GL_RGBA_INTEGER;
|
||||
f.type = GL_UNSIGNED_SHORT;
|
||||
break;
|
||||
case PIXELFORMAT_R32_INT:
|
||||
f.internalformat = GL_R32I;
|
||||
f.externalformat = GL_RED_INTEGER;
|
||||
f.type = GL_INT;
|
||||
break;
|
||||
case PIXELFORMAT_R32_UINT:
|
||||
f.internalformat = GL_R32UI;
|
||||
f.externalformat = GL_RED_INTEGER;
|
||||
f.type = GL_UNSIGNED_INT;
|
||||
break;
|
||||
case PIXELFORMAT_RG32_INT:
|
||||
f.internalformat = GL_RG32I;
|
||||
f.externalformat = GL_RG_INTEGER;
|
||||
f.type = GL_INT;
|
||||
break;
|
||||
case PIXELFORMAT_RG32_UINT:
|
||||
f.internalformat = GL_RG32UI;
|
||||
f.externalformat = GL_RG_INTEGER;
|
||||
f.type = GL_UNSIGNED_INT;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA32_INT:
|
||||
f.internalformat = GL_RGBA32I;
|
||||
f.externalformat = GL_RGBA_INTEGER;
|
||||
f.type = GL_INT;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA32_UINT:
|
||||
f.internalformat = GL_RGBA32UI;
|
||||
f.externalformat = GL_RGBA_INTEGER;
|
||||
f.type = GL_UNSIGNED_INT;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_LA8_UNORM:
|
||||
if (gl.isCoreProfile() || GLAD_ES_VERSION_3_0)
|
||||
{
|
||||
@@ -1785,7 +1942,7 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_DXT1_UNORM:
|
||||
f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_S3TC_DXT1_EXT : GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
|
||||
f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
|
||||
break;
|
||||
case PIXELFORMAT_DXT3_UNORM:
|
||||
f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT : GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
|
||||
@@ -1928,6 +2085,7 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat)
|
||||
{
|
||||
const uint32 commonsample = PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_LINEAR;
|
||||
const uint32 commonrender = PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_BLEND | PIXELFORMATUSAGEFLAGS_MSAA;
|
||||
const uint32 computewrite = PIXELFORMATUSAGEFLAGS_COMPUTEWRITE;
|
||||
|
||||
uint32 flags = PIXELFORMATUSAGEFLAGS_NONE;
|
||||
|
||||
@@ -1939,11 +2097,15 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat)
|
||||
flags |= commonsample | commonrender;
|
||||
else if (pixelformat == PIXELFORMAT_R8_UNORM && (GLAD_ES_VERSION_2_0 || GLAD_VERSION_1_1))
|
||||
flags |= commonsample; // We'll use OpenGL's luminance format internally.
|
||||
if (GLAD_VERSION_4_3)
|
||||
flags |= computewrite;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA8_UNORM:
|
||||
flags |= commonsample;
|
||||
if (GLAD_VERSION_1_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8)
|
||||
flags |= commonrender;
|
||||
if (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_1)
|
||||
flags |= computewrite;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA8_UNORM_sRGB:
|
||||
if (gl.bugs.brokenSRGB)
|
||||
@@ -1953,6 +2115,8 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat)
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0
|
||||
|| ((GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB) && (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB)))
|
||||
flags |= commonrender;
|
||||
if (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_1)
|
||||
flags |= computewrite;
|
||||
break;
|
||||
case PIXELFORMAT_R16_UNORM:
|
||||
case PIXELFORMAT_RG16_UNORM:
|
||||
@@ -1960,10 +2124,14 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat)
|
||||
|| (GLAD_VERSION_1_1 && GLAD_ARB_texture_rg)
|
||||
|| (GLAD_EXT_texture_norm16 && (GLAD_ES_VERSION_3_0 || GLAD_EXT_texture_rg)))
|
||||
flags |= commonsample | commonrender;
|
||||
if (GLAD_VERSION_4_3)
|
||||
flags |= computewrite;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA16_UNORM:
|
||||
if (GLAD_VERSION_1_1 || GLAD_EXT_texture_norm16)
|
||||
flags |= commonsample | commonrender;
|
||||
if (GLAD_VERSION_4_3)
|
||||
flags |= computewrite;
|
||||
break;
|
||||
case PIXELFORMAT_R16_FLOAT:
|
||||
case PIXELFORMAT_RG16_FLOAT:
|
||||
@@ -1975,6 +2143,8 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat)
|
||||
flags |= commonrender;
|
||||
if (!(GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear))
|
||||
flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR;
|
||||
if (GLAD_VERSION_4_3)
|
||||
flags |= computewrite;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA16_FLOAT:
|
||||
if (GLAD_VERSION_3_0 || (GLAD_VERSION_1_0 && GLAD_ARB_texture_float && GLAD_ARB_half_float_pixel))
|
||||
@@ -1985,8 +2155,13 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat)
|
||||
flags |= commonrender;
|
||||
if (!(GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear))
|
||||
flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR;
|
||||
if (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_1)
|
||||
flags |= computewrite;
|
||||
break;
|
||||
case PIXELFORMAT_R32_FLOAT:
|
||||
if (GLAD_ES_VERSION_3_1)
|
||||
flags |= computewrite;
|
||||
// Fallthrough.
|
||||
case PIXELFORMAT_RG32_FLOAT:
|
||||
if (GLAD_VERSION_3_0 || (GLAD_VERSION_1_0 && GLAD_ARB_texture_float && GLAD_ARB_texture_rg))
|
||||
flags |= commonsample | commonrender;
|
||||
@@ -1994,6 +2169,8 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat)
|
||||
flags |= commonsample;
|
||||
if (!(GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear))
|
||||
flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR;
|
||||
if (GLAD_VERSION_4_3)
|
||||
flags |= computewrite;
|
||||
break;
|
||||
case PIXELFORMAT_RGBA32_FLOAT:
|
||||
if (GLAD_VERSION_3_0 || (GLAD_VERSION_1_0 && GLAD_ARB_texture_float))
|
||||
@@ -2002,8 +2179,52 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat)
|
||||
flags |= commonsample;
|
||||
if (!(GLAD_VERSION_1_1 || GLAD_OES_texture_float_linear))
|
||||
flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR;
|
||||
if (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_1)
|
||||
flags |= computewrite;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_R8_INT:
|
||||
case PIXELFORMAT_R8_UINT:
|
||||
case PIXELFORMAT_RG8_INT:
|
||||
case PIXELFORMAT_RG8_UINT:
|
||||
case PIXELFORMAT_RGBA8_INT:
|
||||
case PIXELFORMAT_RGBA8_UINT:
|
||||
case PIXELFORMAT_R16_INT:
|
||||
case PIXELFORMAT_R16_UINT:
|
||||
case PIXELFORMAT_RG16_INT:
|
||||
case PIXELFORMAT_RG16_UINT:
|
||||
case PIXELFORMAT_RGBA16_INT:
|
||||
case PIXELFORMAT_RGBA16_UINT:
|
||||
case PIXELFORMAT_R32_INT:
|
||||
case PIXELFORMAT_R32_UINT:
|
||||
case PIXELFORMAT_RG32_INT:
|
||||
case PIXELFORMAT_RG32_UINT:
|
||||
case PIXELFORMAT_RGBA32_INT:
|
||||
case PIXELFORMAT_RGBA32_UINT:
|
||||
if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0)
|
||||
flags |= PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_RENDERTARGET;
|
||||
if (GLAD_VERSION_4_3)
|
||||
flags |= computewrite;
|
||||
if (GLAD_ES_VERSION_3_1)
|
||||
{
|
||||
switch (pixelformat)
|
||||
{
|
||||
case PIXELFORMAT_RGBA8_INT:
|
||||
case PIXELFORMAT_RGBA8_UINT:
|
||||
case PIXELFORMAT_RGBA16_INT:
|
||||
case PIXELFORMAT_RGBA16_UINT:
|
||||
case PIXELFORMAT_R32_INT:
|
||||
case PIXELFORMAT_R32_UINT:
|
||||
case PIXELFORMAT_RGBA32_INT:
|
||||
case PIXELFORMAT_RGBA32_UINT:
|
||||
flags |= computewrite;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_LA8_UNORM:
|
||||
flags |= commonsample;
|
||||
break;
|
||||
@@ -2019,12 +2240,16 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat)
|
||||
case PIXELFORMAT_RGB10A2_UNORM:
|
||||
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0)
|
||||
flags |= commonsample | commonrender;
|
||||
if (GLAD_VERSION_4_3)
|
||||
flags |= computewrite;
|
||||
break;
|
||||
case PIXELFORMAT_RG11B10_FLOAT:
|
||||
if (GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_texture_packed_float)
|
||||
flags |= commonsample;
|
||||
if (GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_color_buffer_packed_float)
|
||||
flags |= commonrender;
|
||||
if (GLAD_VERSION_4_3)
|
||||
flags |= computewrite;
|
||||
break;
|
||||
|
||||
case PIXELFORMAT_STENCIL8:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -185,6 +185,13 @@ public:
|
||||
**/
|
||||
bool brokenSRGB;
|
||||
|
||||
/**
|
||||
* Some Android graphics drivers claim to support GLES3.0 but have bugs
|
||||
* with certain aspects that users expect to work. For example:
|
||||
* https://github.com/love2d/love-android/issues/204
|
||||
**/
|
||||
bool brokenGLES3;
|
||||
|
||||
/**
|
||||
* Other bugs which have workarounds that don't use conditional code at
|
||||
* the moment:
|
||||
@@ -305,7 +312,7 @@ public:
|
||||
/**
|
||||
* Gets the ID for love's default texture (used for "untextured" primitives.)
|
||||
**/
|
||||
GLuint getDefaultTexture(TextureType type) const;
|
||||
GLuint getDefaultTexture(TextureType type, DataBaseType datatype) const;
|
||||
|
||||
/**
|
||||
* Gets the texture ID for love's default texel buffer.
|
||||
@@ -383,6 +390,14 @@ public:
|
||||
**/
|
||||
int getMaxShaderStorageBufferSize() const;
|
||||
|
||||
/**
|
||||
* Returns the maximum number of compute work groups that can be
|
||||
* dispatched in a given dimension.
|
||||
*/
|
||||
int getMaxComputeWorkGroupsX() const;
|
||||
int getMaxComputeWorkGroupsY() const;
|
||||
int getMaxComputeWorkGroupsZ() const;
|
||||
|
||||
/**
|
||||
* Returns the maximum supported number of simultaneous render targets.
|
||||
**/
|
||||
@@ -467,6 +482,9 @@ private:
|
||||
int maxTextureArrayLayers;
|
||||
int maxTexelBufferSize;
|
||||
int maxShaderStorageBufferSize;
|
||||
int maxComputeWorkGroupsX;
|
||||
int maxComputeWorkGroupsY;
|
||||
int maxComputeWorkGroupsZ;
|
||||
int maxRenderTargets;
|
||||
int maxSamples;
|
||||
int maxTextureUnits;
|
||||
@@ -505,7 +523,7 @@ private:
|
||||
|
||||
GLuint boundFramebuffers[2];
|
||||
|
||||
GLuint defaultTexture[TEXTURE_MAX_ENUM];
|
||||
GLuint defaultTexture[TEXTURE_MAX_ENUM][DATA_BASETYPE_MAX_ENUM];
|
||||
GLuint defaultTexelBuffer;
|
||||
GLuint defaultStorageBuffer;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -43,8 +43,8 @@ static bool isBuffer(Shader::UniformType utype)
|
||||
return utype == Shader::UNIFORM_TEXELBUFFER || utype == Shader::UNIFORM_STORAGEBUFFER;
|
||||
}
|
||||
|
||||
Shader::Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel)
|
||||
: love::graphics::Shader(vertex, pixel)
|
||||
Shader::Shader(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM])
|
||||
: love::graphics::Shader(stages)
|
||||
, program(0)
|
||||
, builtinUniforms()
|
||||
, builtinUniformInfo()
|
||||
@@ -63,7 +63,7 @@ Shader::~Shader()
|
||||
if (p.second.data != nullptr)
|
||||
free(p.second.data);
|
||||
|
||||
if (p.second.baseType == UNIFORM_SAMPLER)
|
||||
if (p.second.baseType == UNIFORM_SAMPLER || p.second.baseType == UNIFORM_STORAGETEXTURE)
|
||||
{
|
||||
for (int i = 0; i < p.second.count; i++)
|
||||
{
|
||||
@@ -119,15 +119,8 @@ void Shader::mapActiveUniforms()
|
||||
|
||||
u.name = std::string(cname, (size_t) namelen);
|
||||
u.location = glGetUniformLocation(program, u.name.c_str());
|
||||
u.baseType = getUniformBaseType(gltype);
|
||||
u.textureType = getUniformTextureType(gltype);
|
||||
u.dataBaseType = getUniformTexelBaseType(gltype);
|
||||
u.isDepthSampler = isDepthTextureType(gltype);
|
||||
|
||||
if (u.baseType == UNIFORM_MATRIX)
|
||||
u.matrix = getMatrixSize(gltype);
|
||||
else
|
||||
u.components = getUniformTypeComponents(gltype);
|
||||
u.access = ACCESS_READ;
|
||||
computeUniformTypeInfo(gltype, u);
|
||||
|
||||
// glGetActiveUniform appends "[0]" to the end of array uniform names...
|
||||
if (u.name.length() > 3)
|
||||
@@ -159,12 +152,39 @@ void Shader::mapActiveUniforms()
|
||||
else
|
||||
{
|
||||
unit.isTexelBuffer = false;
|
||||
unit.texture = gl.getDefaultTexture(u.textureType);
|
||||
unit.texture = gl.getDefaultTexture(u.textureType, u.dataBaseType);
|
||||
}
|
||||
|
||||
for (int i = 0; i < u.count; i++)
|
||||
textureUnits.push_back(unit);
|
||||
}
|
||||
else if (u.baseType == UNIFORM_STORAGETEXTURE)
|
||||
{
|
||||
const auto reflectionit = validationReflection.storageTextures.find(u.name);
|
||||
if (reflectionit != validationReflection.storageTextures.end())
|
||||
{
|
||||
u.storageTextureFormat = reflectionit->second.format;
|
||||
u.access = reflectionit->second.access;
|
||||
}
|
||||
|
||||
StorageTextureBinding binding = {};
|
||||
binding.gltexture = gl.getDefaultTexture(u.textureType, u.dataBaseType);
|
||||
binding.type = u.textureType;
|
||||
|
||||
if ((u.access & (ACCESS_READ | ACCESS_WRITE)) != 0)
|
||||
binding.access = GL_READ_WRITE;
|
||||
else if ((u.access & ACCESS_WRITE) != 0)
|
||||
binding.access = GL_WRITE_ONLY;
|
||||
else if ((u.access & ACCESS_READ) != 0)
|
||||
binding.access = GL_READ_ONLY;
|
||||
|
||||
bool sRGB = false;
|
||||
auto fmt = OpenGL::convertPixelFormat(u.storageTextureFormat, false, sRGB);
|
||||
binding.internalFormat = fmt.internalformat;
|
||||
|
||||
for (int i = 0; i < u.count; i++)
|
||||
storageTextureBindings.push_back(binding);
|
||||
}
|
||||
|
||||
// Make sure previously set uniform data is preserved, and shader-
|
||||
// initialized values are retrieved.
|
||||
@@ -190,6 +210,7 @@ void Shader::mapActiveUniforms()
|
||||
case UNIFORM_INT:
|
||||
case UNIFORM_BOOL:
|
||||
case UNIFORM_SAMPLER:
|
||||
case UNIFORM_STORAGETEXTURE:
|
||||
case UNIFORM_TEXELBUFFER:
|
||||
u.dataSize = sizeof(int) * u.components * u.count;
|
||||
u.data = malloc(u.dataSize);
|
||||
@@ -233,6 +254,17 @@ void Shader::mapActiveUniforms()
|
||||
memset(u.textures, 0, sizeof(Texture *) * u.count);
|
||||
}
|
||||
}
|
||||
else if (u.baseType == UNIFORM_STORAGETEXTURE)
|
||||
{
|
||||
int startbinding = (int) storageTextureBindings.size() - u.count;
|
||||
for (int i = 0; i < u.count; i++)
|
||||
u.ints[i] = startbinding + i;
|
||||
|
||||
glUniform1iv(u.location, u.count, u.ints);
|
||||
|
||||
u.textures = new love::graphics::Texture*[u.count];
|
||||
memset(u.textures, 0, sizeof(Texture *) * u.count);
|
||||
}
|
||||
}
|
||||
|
||||
size_t offset = 0;
|
||||
@@ -284,7 +316,7 @@ void Shader::mapActiveUniforms()
|
||||
if (builtin != BUILTIN_MAX_ENUM)
|
||||
builtinUniformInfo[(int)builtin] = &uniforms[u.name];
|
||||
|
||||
if (u.baseType == UNIFORM_SAMPLER)
|
||||
if (u.baseType == UNIFORM_SAMPLER || u.baseType == UNIFORM_STORAGETEXTURE)
|
||||
{
|
||||
// Make sure all stored textures have their Volatiles loaded before
|
||||
// the sendTextures call, since it calls getHandle().
|
||||
@@ -325,6 +357,7 @@ void Shader::mapActiveUniforms()
|
||||
{
|
||||
UniformInfo u = {};
|
||||
u.baseType = UNIFORM_STORAGEBUFFER;
|
||||
u.access = ACCESS_READ;
|
||||
|
||||
GLsizei namelength = 0;
|
||||
glGetProgramResourceName(program, GL_SHADER_STORAGE_BLOCK, sindex, 2048, &namelength, namebuffer);
|
||||
@@ -337,6 +370,7 @@ void Shader::mapActiveUniforms()
|
||||
{
|
||||
u.bufferStride = reflectionit->second.stride;
|
||||
u.bufferMemberCount = reflectionit->second.memberCount;
|
||||
u.access = reflectionit->second.access;
|
||||
}
|
||||
|
||||
// Make sure previously set uniform data is preserved, and shader-
|
||||
@@ -369,10 +403,17 @@ void Shader::mapActiveUniforms()
|
||||
if (binding.bindingindex >= 0)
|
||||
{
|
||||
int activeindex = (int)activeStorageBufferBindings.size();
|
||||
|
||||
storageBufferBindingIndexToActiveBinding[binding.bindingindex] = activeindex;
|
||||
|
||||
activeStorageBufferBindings.push_back(binding);
|
||||
|
||||
auto p = std::make_pair(activeindex, -1);
|
||||
|
||||
if (u.access & ACCESS_WRITE)
|
||||
{
|
||||
p.second = (int)activeWritableStorageBuffers.size();
|
||||
activeWritableStorageBuffers.push_back(u.buffers[0]);
|
||||
}
|
||||
|
||||
storageBufferBindingIndexToActiveBinding[binding.bindingindex] = p;
|
||||
}
|
||||
|
||||
uniforms[u.name] = u;
|
||||
@@ -399,7 +440,7 @@ void Shader::mapActiveUniforms()
|
||||
if (p.second.data != nullptr)
|
||||
free(p.second.data);
|
||||
|
||||
if (p.second.baseType == UNIFORM_SAMPLER)
|
||||
if (p.second.baseType == UNIFORM_SAMPLER || p.second.baseType == UNIFORM_STORAGETEXTURE)
|
||||
{
|
||||
for (int i = 0; i < p.second.count; i++)
|
||||
{
|
||||
@@ -433,9 +474,12 @@ bool Shader::loadVolatile()
|
||||
textureUnits.clear();
|
||||
textureUnits.push_back(TextureUnit());
|
||||
|
||||
storageBufferBindingIndexToActiveBinding.resize(gl.getMaxShaderStorageBufferBindings(), -1);
|
||||
activeStorageBufferBindings.clear();
|
||||
|
||||
storageBufferBindingIndexToActiveBinding.resize(gl.getMaxShaderStorageBufferBindings(), std::make_pair(-1, -1));
|
||||
activeStorageBufferBindings.clear();
|
||||
activeWritableStorageBuffers.clear();
|
||||
|
||||
for (const auto &stage : stages)
|
||||
{
|
||||
if (stage.get() != nullptr)
|
||||
@@ -561,7 +605,7 @@ void Shader::attach()
|
||||
// retain/release happens in Graphics::setShader.
|
||||
|
||||
// Make sure all textures are bound to their respective texture units.
|
||||
for (int i = 0; i < (int) textureUnits.size(); ++i)
|
||||
for (int i = 0; i < (int) textureUnits.size(); i++)
|
||||
{
|
||||
const TextureUnit &unit = textureUnits[i];
|
||||
if (unit.active)
|
||||
@@ -573,6 +617,12 @@ void Shader::attach()
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < storageTextureBindings.size(); i++)
|
||||
{
|
||||
const auto &binding = storageTextureBindings[i];
|
||||
glBindImageTexture((GLuint) i, binding.gltexture, 0, GL_TRUE, 0, binding.access, binding.internalFormat);
|
||||
}
|
||||
|
||||
for (auto bufferbinding : activeStorageBufferBindings)
|
||||
gl.bindIndexedBuffer(bufferbinding.buffer, BUFFERUSAGE_SHADER_STORAGE, bufferbinding.bindingindex);
|
||||
|
||||
@@ -636,7 +686,7 @@ void Shader::updateUniform(const UniformInfo *info, int count, bool internalupda
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (type == UNIFORM_INT || type == UNIFORM_BOOL || type == UNIFORM_SAMPLER || type == UNIFORM_TEXELBUFFER)
|
||||
else if (type == UNIFORM_INT || type == UNIFORM_BOOL || type == UNIFORM_SAMPLER || type == UNIFORM_STORAGETEXTURE || type == UNIFORM_TEXELBUFFER)
|
||||
{
|
||||
switch (info->components)
|
||||
{
|
||||
@@ -705,7 +755,10 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
|
||||
|
||||
void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count, bool internalUpdate)
|
||||
{
|
||||
if (info->baseType != UNIFORM_SAMPLER)
|
||||
bool issampler = info->baseType == UNIFORM_SAMPLER;
|
||||
bool isstoragetex = info->baseType == UNIFORM_STORAGETEXTURE;
|
||||
|
||||
if (!issampler && !isstoragetex)
|
||||
return;
|
||||
|
||||
bool shaderactive = current == this;
|
||||
@@ -732,19 +785,39 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex
|
||||
|
||||
info->textures[i] = tex;
|
||||
|
||||
GLuint gltex = 0;
|
||||
if (textures[i] != nullptr)
|
||||
gltex = (GLuint) tex->getHandle();
|
||||
if (isstoragetex)
|
||||
{
|
||||
GLuint gltex = 0;
|
||||
if (tex != nullptr)
|
||||
gltex = (GLuint) tex->getHandle();
|
||||
else
|
||||
gltex = gl.getDefaultTexture(info->textureType, info->dataBaseType);
|
||||
|
||||
int bindingindex = info->ints[i];
|
||||
auto &binding = storageTextureBindings[bindingindex];
|
||||
|
||||
binding.texture = tex;
|
||||
binding.gltexture = gltex;
|
||||
|
||||
if (shaderactive)
|
||||
glBindImageTexture(bindingindex, binding.gltexture, 0, GL_TRUE, 0, binding.access, binding.internalFormat);
|
||||
}
|
||||
else
|
||||
gltex = gl.getDefaultTexture(info->textureType);
|
||||
{
|
||||
GLuint gltex = 0;
|
||||
if (textures[i] != nullptr)
|
||||
gltex = (GLuint) tex->getHandle();
|
||||
else
|
||||
gltex = gl.getDefaultTexture(info->textureType, info->dataBaseType);
|
||||
|
||||
int texunit = info->ints[i];
|
||||
int texunit = info->ints[i];
|
||||
|
||||
if (shaderactive)
|
||||
gl.bindTextureToUnit(info->textureType, gltex, texunit, false, false);
|
||||
if (shaderactive)
|
||||
gl.bindTextureToUnit(info->textureType, gltex, texunit, false, false);
|
||||
|
||||
// Store texture id so it can be re-bound to the texture unit later.
|
||||
textureUnits[texunit].texture = gltex;
|
||||
// Store texture id so it can be re-bound to the texture unit later.
|
||||
textureUnits[texunit].texture = gltex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,7 +861,7 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe
|
||||
if (texelbinding)
|
||||
{
|
||||
GLuint gltex = 0;
|
||||
if (buffers[i] != nullptr)
|
||||
if (buffer != nullptr)
|
||||
gltex = (GLuint) buffer->getTexelBufferHandle();
|
||||
else
|
||||
gltex = gl.getDefaultTexelBuffer();
|
||||
@@ -806,7 +879,7 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe
|
||||
int bindingindex = info->ints[i];
|
||||
|
||||
GLuint glbuffer = 0;
|
||||
if (buffers[i] != nullptr)
|
||||
if (buffer != nullptr)
|
||||
glbuffer = (GLuint) buffer->getHandle();
|
||||
else
|
||||
glbuffer = gl.getDefaultStorageBuffer();
|
||||
@@ -814,9 +887,13 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe
|
||||
if (shaderactive)
|
||||
gl.bindIndexedBuffer(glbuffer, BUFFERUSAGE_SHADER_STORAGE, bindingindex);
|
||||
|
||||
int activeindex = storageBufferBindingIndexToActiveBinding[bindingindex];
|
||||
if (activeindex >= 0)
|
||||
activeStorageBufferBindings[activeindex].buffer = glbuffer;
|
||||
auto activeindex = storageBufferBindingIndexToActiveBinding[bindingindex];
|
||||
|
||||
if (activeindex.first >= 0)
|
||||
activeStorageBufferBindings[activeindex.first].buffer = glbuffer;
|
||||
|
||||
if (activeindex.second >= 0)
|
||||
activeWritableStorageBuffers[activeindex.second] = buffer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -928,11 +1005,6 @@ void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW,
|
||||
|
||||
int Shader::getUniformTypeComponents(GLenum type) const
|
||||
{
|
||||
UniformType basetype = getUniformBaseType(type);
|
||||
|
||||
if (basetype == UNIFORM_SAMPLER || basetype == UNIFORM_TEXELBUFFER)
|
||||
return 1;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case GL_INT:
|
||||
@@ -1007,25 +1079,35 @@ Shader::MatrixSize Shader::getMatrixSize(GLenum type) const
|
||||
return m;
|
||||
}
|
||||
|
||||
Shader::UniformType Shader::getUniformBaseType(GLenum type) const
|
||||
void Shader::computeUniformTypeInfo(GLenum type, UniformInfo &u)
|
||||
{
|
||||
u.isDepthSampler = false;
|
||||
u.components = getUniformTypeComponents(type);
|
||||
u.baseType = UNIFORM_UNKNOWN;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case GL_INT:
|
||||
case GL_INT_VEC2:
|
||||
case GL_INT_VEC3:
|
||||
case GL_INT_VEC4:
|
||||
return UNIFORM_INT;
|
||||
u.baseType = UNIFORM_INT;
|
||||
u.dataBaseType = DATA_BASETYPE_INT;
|
||||
break;
|
||||
case GL_UNSIGNED_INT:
|
||||
case GL_UNSIGNED_INT_VEC2:
|
||||
case GL_UNSIGNED_INT_VEC3:
|
||||
case GL_UNSIGNED_INT_VEC4:
|
||||
return UNIFORM_UINT;
|
||||
u.baseType = UNIFORM_UINT;
|
||||
u.dataBaseType = DATA_BASETYPE_UINT;
|
||||
break;
|
||||
case GL_FLOAT:
|
||||
case GL_FLOAT_VEC2:
|
||||
case GL_FLOAT_VEC3:
|
||||
case GL_FLOAT_VEC4:
|
||||
return UNIFORM_FLOAT;
|
||||
u.baseType = UNIFORM_FLOAT;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
break;
|
||||
case GL_FLOAT_MAT2:
|
||||
case GL_FLOAT_MAT3:
|
||||
case GL_FLOAT_MAT4:
|
||||
@@ -1035,105 +1117,173 @@ Shader::UniformType Shader::getUniformBaseType(GLenum type) const
|
||||
case GL_FLOAT_MAT3x4:
|
||||
case GL_FLOAT_MAT4x2:
|
||||
case GL_FLOAT_MAT4x3:
|
||||
return UNIFORM_MATRIX;
|
||||
u.baseType = UNIFORM_MATRIX;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.matrix = getMatrixSize(type);
|
||||
break;
|
||||
case GL_BOOL:
|
||||
case GL_BOOL_VEC2:
|
||||
case GL_BOOL_VEC3:
|
||||
case GL_BOOL_VEC4:
|
||||
return UNIFORM_BOOL;
|
||||
case GL_SAMPLER_1D:
|
||||
case GL_SAMPLER_1D_SHADOW:
|
||||
case GL_SAMPLER_1D_ARRAY:
|
||||
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
||||
u.baseType = UNIFORM_BOOL;
|
||||
u.dataBaseType = DATA_BASETYPE_BOOL;
|
||||
break;
|
||||
|
||||
case GL_SAMPLER_2D:
|
||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
case GL_SAMPLER_2D_RECT:
|
||||
case GL_SAMPLER_2D_RECT_SHADOW:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.textureType = TEXTURE_2D;
|
||||
break;
|
||||
case GL_SAMPLER_2D_SHADOW:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.textureType = TEXTURE_2D;
|
||||
u.isDepthSampler = true;
|
||||
break;
|
||||
case GL_INT_SAMPLER_2D:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_INT;
|
||||
u.textureType = TEXTURE_2D;
|
||||
break;
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_UINT;
|
||||
u.textureType = TEXTURE_2D;
|
||||
break;
|
||||
case GL_SAMPLER_2D_ARRAY:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.textureType = TEXTURE_2D_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.textureType = TEXTURE_2D_ARRAY;
|
||||
u.isDepthSampler = true;
|
||||
break;
|
||||
case GL_INT_SAMPLER_2D_ARRAY:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_INT;
|
||||
u.textureType = TEXTURE_2D_ARRAY;
|
||||
break;
|
||||
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_UINT;
|
||||
u.textureType = TEXTURE_2D_ARRAY;
|
||||
break;
|
||||
case GL_SAMPLER_3D:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.textureType = TEXTURE_VOLUME;
|
||||
break;
|
||||
case GL_INT_SAMPLER_3D:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_INT;
|
||||
u.textureType = TEXTURE_VOLUME;
|
||||
break;
|
||||
case GL_UNSIGNED_INT_SAMPLER_3D:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_UINT;
|
||||
u.textureType = TEXTURE_VOLUME;
|
||||
break;
|
||||
case GL_SAMPLER_CUBE:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.textureType = TEXTURE_CUBE;
|
||||
break;
|
||||
case GL_SAMPLER_CUBE_SHADOW:
|
||||
case GL_SAMPLER_CUBE_MAP_ARRAY:
|
||||
case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
|
||||
return UNIFORM_SAMPLER;
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.textureType = TEXTURE_CUBE;
|
||||
u.isDepthSampler = true;
|
||||
break;
|
||||
case GL_INT_SAMPLER_CUBE:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_INT;
|
||||
u.textureType = TEXTURE_CUBE;
|
||||
break;
|
||||
case GL_UNSIGNED_INT_SAMPLER_CUBE:
|
||||
u.baseType = UNIFORM_SAMPLER;
|
||||
u.dataBaseType = DATA_BASETYPE_UINT;
|
||||
u.textureType = TEXTURE_CUBE;
|
||||
break;
|
||||
|
||||
case GL_SAMPLER_BUFFER:
|
||||
u.baseType = UNIFORM_TEXELBUFFER;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
break;
|
||||
case GL_INT_SAMPLER_BUFFER:
|
||||
u.baseType = UNIFORM_TEXELBUFFER;
|
||||
u.dataBaseType = DATA_BASETYPE_INT;
|
||||
break;
|
||||
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
|
||||
return UNIFORM_TEXELBUFFER;
|
||||
default:
|
||||
return UNIFORM_UNKNOWN;
|
||||
}
|
||||
}
|
||||
u.baseType = UNIFORM_TEXELBUFFER;
|
||||
u.dataBaseType = DATA_BASETYPE_UINT;
|
||||
break;
|
||||
|
||||
TextureType Shader::getUniformTextureType(GLenum type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GL_SAMPLER_1D:
|
||||
case GL_SAMPLER_1D_SHADOW:
|
||||
case GL_SAMPLER_1D_ARRAY:
|
||||
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
||||
// 1D-typed textures are not supported.
|
||||
return TEXTURE_MAX_ENUM;
|
||||
case GL_SAMPLER_2D:
|
||||
case GL_SAMPLER_2D_SHADOW:
|
||||
return TEXTURE_2D;
|
||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
// Multisample textures are not supported.
|
||||
return TEXTURE_MAX_ENUM;
|
||||
case GL_SAMPLER_2D_RECT:
|
||||
case GL_SAMPLER_2D_RECT_SHADOW:
|
||||
// Rectangle textures are not supported.
|
||||
return TEXTURE_MAX_ENUM;
|
||||
case GL_SAMPLER_2D_ARRAY:
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
return TEXTURE_2D_ARRAY;
|
||||
case GL_SAMPLER_3D:
|
||||
return TEXTURE_VOLUME;
|
||||
case GL_SAMPLER_CUBE:
|
||||
case GL_SAMPLER_CUBE_SHADOW:
|
||||
return TEXTURE_CUBE;
|
||||
case GL_SAMPLER_CUBE_MAP_ARRAY:
|
||||
case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
|
||||
// Cubemap array textures are not supported.
|
||||
return TEXTURE_MAX_ENUM;
|
||||
default:
|
||||
return TEXTURE_MAX_ENUM;
|
||||
}
|
||||
}
|
||||
case GL_IMAGE_2D:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.textureType = TEXTURE_2D;
|
||||
break;
|
||||
case GL_INT_IMAGE_2D:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_INT;
|
||||
u.textureType = TEXTURE_2D;
|
||||
break;
|
||||
case GL_UNSIGNED_INT_IMAGE_2D:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_UINT;
|
||||
u.textureType = TEXTURE_2D;
|
||||
break;
|
||||
case GL_IMAGE_2D_ARRAY:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.textureType = TEXTURE_2D_ARRAY;
|
||||
break;
|
||||
case GL_INT_IMAGE_2D_ARRAY:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_INT;
|
||||
u.textureType = TEXTURE_2D_ARRAY;
|
||||
break;
|
||||
case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_UINT;
|
||||
u.textureType = TEXTURE_2D_ARRAY;
|
||||
break;
|
||||
case GL_IMAGE_3D:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.textureType = TEXTURE_VOLUME;
|
||||
break;
|
||||
case GL_INT_IMAGE_3D:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_INT;
|
||||
u.textureType = TEXTURE_VOLUME;
|
||||
break;
|
||||
case GL_UNSIGNED_INT_IMAGE_3D:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_UINT;
|
||||
u.textureType = TEXTURE_VOLUME;
|
||||
break;
|
||||
case GL_IMAGE_CUBE:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_FLOAT;
|
||||
u.textureType = TEXTURE_CUBE;
|
||||
break;
|
||||
case GL_INT_IMAGE_CUBE:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_INT;
|
||||
u.textureType = TEXTURE_CUBE;
|
||||
break;
|
||||
case GL_UNSIGNED_INT_IMAGE_CUBE:
|
||||
u.baseType = UNIFORM_STORAGETEXTURE;
|
||||
u.dataBaseType = DATA_BASETYPE_UINT;
|
||||
u.textureType = TEXTURE_CUBE;
|
||||
break;
|
||||
|
||||
DataBaseType Shader::getUniformTexelBaseType(GLenum type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GL_SAMPLER_BUFFER:
|
||||
return DATA_BASETYPE_FLOAT;
|
||||
case GL_INT_SAMPLER_BUFFER:
|
||||
return DATA_BASETYPE_INT;
|
||||
case GL_UNSIGNED_INT_SAMPLER_BUFFER:
|
||||
return DATA_BASETYPE_UINT;
|
||||
default:
|
||||
return DATA_BASETYPE_MAX_ENUM;
|
||||
}
|
||||
}
|
||||
|
||||
bool Shader::isDepthTextureType(GLenum type) const
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case GL_SAMPLER_1D_SHADOW:
|
||||
case GL_SAMPLER_1D_ARRAY_SHADOW:
|
||||
case GL_SAMPLER_2D_SHADOW:
|
||||
case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
case GL_SAMPLER_CUBE_SHADOW:
|
||||
case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -43,7 +43,16 @@ class Shader final : public love::graphics::Shader, public Volatile
|
||||
{
|
||||
public:
|
||||
|
||||
Shader(love::graphics::ShaderStage *vertex, love::graphics::ShaderStage *pixel);
|
||||
struct StorageTextureBinding
|
||||
{
|
||||
Texture *texture = nullptr;
|
||||
GLuint gltexture = 0;
|
||||
TextureType type = TEXTURE_2D;
|
||||
GLenum access = GL_READ_ONLY;
|
||||
GLenum internalFormat;
|
||||
};
|
||||
|
||||
Shader(StrongRef<love::graphics::ShaderStage> stages[SHADERSTAGE_MAX_ENUM]);
|
||||
virtual ~Shader();
|
||||
|
||||
// Implements Volatile
|
||||
@@ -65,6 +74,9 @@ public:
|
||||
|
||||
void updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, int viewportH);
|
||||
|
||||
const std::vector<Buffer *> &getActiveWritableStorageBuffers() const { return activeWritableStorageBuffers; }
|
||||
const std::vector<StorageTextureBinding> &getStorageTextureBindings() const { return storageTextureBindings; }
|
||||
|
||||
private:
|
||||
|
||||
struct TextureUnit
|
||||
@@ -89,11 +101,8 @@ private:
|
||||
void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count, bool internalupdate);
|
||||
|
||||
int getUniformTypeComponents(GLenum type) const;
|
||||
void computeUniformTypeInfo(GLenum type, UniformInfo &u);
|
||||
MatrixSize getMatrixSize(GLenum type) const;
|
||||
UniformType getUniformBaseType(GLenum type) const;
|
||||
TextureType getUniformTextureType(GLenum type) const;
|
||||
DataBaseType getUniformTexelBaseType(GLenum type) const;
|
||||
bool isDepthTextureType(GLenum type) const;
|
||||
|
||||
void flushBatchedDraws() const;
|
||||
|
||||
@@ -115,9 +124,13 @@ private:
|
||||
// Texture unit pool for setting textures
|
||||
std::vector<TextureUnit> textureUnits;
|
||||
|
||||
std::vector<int> storageBufferBindingIndexToActiveBinding;
|
||||
std::vector<StorageTextureBinding> storageTextureBindings;
|
||||
|
||||
std::vector<std::pair<int, int>> storageBufferBindingIndexToActiveBinding;
|
||||
std::vector<BufferBinding> activeStorageBufferBindings;
|
||||
|
||||
std::vector<Buffer *> activeWritableStorageBuffers;
|
||||
|
||||
std::vector<std::pair<const UniformInfo *, int>> pendingUniformUpdates;
|
||||
|
||||
}; // Shader
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -27,7 +27,7 @@ namespace graphics
|
||||
namespace opengl
|
||||
{
|
||||
|
||||
ShaderStage::ShaderStage(love::graphics::Graphics *gfx, StageType stage, const std::string &source, bool gles, const std::string &cachekey)
|
||||
ShaderStage::ShaderStage(love::graphics::Graphics *gfx, ShaderStageType stage, const std::string &source, bool gles, const std::string &cachekey)
|
||||
: love::graphics::ShaderStage(gfx, stage, source, gles, cachekey)
|
||||
, glShader(0)
|
||||
{
|
||||
@@ -44,15 +44,17 @@ bool ShaderStage::loadVolatile()
|
||||
if (glShader != 0)
|
||||
return true;
|
||||
|
||||
StageType stage = getStageType();
|
||||
ShaderStageType stage = getStageType();
|
||||
const char *typestr = "unknown";
|
||||
getConstant(stage, typestr);
|
||||
|
||||
GLenum glstage = 0;
|
||||
if (stage == STAGE_VERTEX)
|
||||
if (stage == SHADERSTAGE_VERTEX)
|
||||
glstage = GL_VERTEX_SHADER;
|
||||
else if (stage == STAGE_PIXEL)
|
||||
else if (stage == SHADERSTAGE_PIXEL)
|
||||
glstage = GL_FRAGMENT_SHADER;
|
||||
else if (stage == SHADERSTAGE_COMPUTE)
|
||||
glstage = GL_COMPUTE_SHADER;
|
||||
else
|
||||
throw love::Exception("%s shader stage is not handled in OpenGL backend code.", typestr);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
@@ -35,7 +35,7 @@ class ShaderStage final : public love::graphics::ShaderStage, public Volatile
|
||||
{
|
||||
public:
|
||||
|
||||
ShaderStage(love::graphics::Graphics *gfx, StageType stage, const std::string &source, bool gles, const std::string &cachekey);
|
||||
ShaderStage(love::graphics::Graphics *gfx, ShaderStageType stage, const std::string &source, bool gles, const std::string &cachekey);
|
||||
virtual ~ShaderStage();
|
||||
|
||||
ptrdiff_t getHandle() const override { return glShader; }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2020 LOVE Development Team
|
||||
* Copyright (c) 2006-2021 LOVE Development Team
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
Reference in New Issue
Block a user