mirror of
https://github.com/love2d/love.git
synced 2026-08-16 16:20:42 +02:00
Add Depth compare / shadow sampler support. Officially this is only supported in glsl3 shaders.
- Add Texture:setDepthSampleMode(comparemode). Only works on textures with depth pixel formats. A texture with the depth sample mode set will only work with a depth sampler. - Add DepthImage, DepthArrayImage, and DepthCubeImage sampler keywords to glsl3. --HG-- branch : minor
This commit is contained in:
@@ -277,6 +277,7 @@ bool Canvas::loadVolatile()
|
||||
|
||||
setFilter(filter);
|
||||
setWrap(wrap);
|
||||
setDepthSampleMode(depthCompareMode);
|
||||
|
||||
while (glGetError() != GL_NO_ERROR)
|
||||
/* Clear the error buffer. */;
|
||||
@@ -358,6 +359,8 @@ void Canvas::setFilter(const Texture::Filter &f)
|
||||
if (!validateFilter(f, false))
|
||||
throw love::Exception("Invalid texture filter.");
|
||||
|
||||
Graphics::flushStreamDrawsGlobal();
|
||||
|
||||
filter = f;
|
||||
gl.bindTextureToUnit(this, 0, false);
|
||||
gl.setTextureFilter(texType, filter);
|
||||
@@ -365,6 +368,8 @@ void Canvas::setFilter(const Texture::Filter &f)
|
||||
|
||||
bool Canvas::setWrap(const Texture::Wrap &w)
|
||||
{
|
||||
Graphics::flushStreamDrawsGlobal();
|
||||
|
||||
bool success = true;
|
||||
bool forceclamp = texType == TEXTURE_CUBE;
|
||||
wrap = w;
|
||||
@@ -402,6 +407,42 @@ bool Canvas::setMipmapSharpness(float /*sharpness*/)
|
||||
return false;
|
||||
}
|
||||
|
||||
void Canvas::setDepthSampleMode(Optional<CompareMode> mode)
|
||||
{
|
||||
Texture::setDepthSampleMode(mode);
|
||||
|
||||
bool supported = gl.isDepthCompareSampleSupported();
|
||||
|
||||
if (mode.hasValue && !supported)
|
||||
throw love::Exception("Depth comparison sampling in shaders is not supported on this system.");
|
||||
|
||||
if (mode.hasValue)
|
||||
{
|
||||
Graphics::flushStreamDrawsGlobal();
|
||||
|
||||
gl.bindTextureToUnit(texType, texture, 0, false);
|
||||
GLenum gltextype = OpenGL::getGLTextureType(texType);
|
||||
|
||||
// See the comment in depthstencil.h
|
||||
GLenum glmode = OpenGL::getGLCompareMode(getReversedCompareMode(mode.value));
|
||||
|
||||
glTexParameteri(gltextype, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE);
|
||||
glTexParameteri(gltextype, GL_TEXTURE_COMPARE_FUNC, glmode);
|
||||
|
||||
}
|
||||
else if (isPixelFormatDepth(format) && supported)
|
||||
{
|
||||
Graphics::flushStreamDrawsGlobal();
|
||||
|
||||
gl.bindTextureToUnit(texType, texture, 0, false);
|
||||
GLenum gltextype = OpenGL::getGLTextureType(texType);
|
||||
|
||||
glTexParameteri(gltextype, GL_TEXTURE_COMPARE_MODE, GL_NONE);
|
||||
}
|
||||
|
||||
depthCompareMode = mode;
|
||||
}
|
||||
|
||||
ptrdiff_t Canvas::getHandle() const
|
||||
{
|
||||
return texture;
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
void setFilter(const Texture::Filter &f) override;
|
||||
bool setWrap(const Texture::Wrap &w) override;
|
||||
bool setMipmapSharpness(float sharpness) override;
|
||||
void setDepthSampleMode(Optional<CompareMode> mode) override;
|
||||
ptrdiff_t getHandle() const override;
|
||||
|
||||
love::image::ImageData *newImageData(love::image::Image *module, int slice, int x, int y, int w, int h) override;
|
||||
|
||||
@@ -354,12 +354,6 @@ void Graphics::flushStreamDraws()
|
||||
prevdefaultshader = Shader::current;
|
||||
Shader::standardShaders[Shader::STANDARD_ARRAY]->attach();
|
||||
}
|
||||
|
||||
if (!sbstate.texture->isReadable())
|
||||
throw love::Exception("Textures with non-readable formats cannot be drawn.");
|
||||
|
||||
if (Shader::current)
|
||||
Shader::current->checkMainTextureType(textype);
|
||||
}
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("Stream vertices flush and draw");
|
||||
@@ -1236,45 +1230,15 @@ void Graphics::setStencilTest(CompareMode compare, int value)
|
||||
return;
|
||||
}
|
||||
|
||||
GLenum glcompare = GL_EQUAL;
|
||||
|
||||
/**
|
||||
* Q: Why are some of the compare modes inverted (e.g. COMPARE_LESS becomes
|
||||
* GL_GREATER)?
|
||||
*
|
||||
* A: OpenGL / GPUs do the comparison in the opposite way that makes sense
|
||||
* OpenGL / GPUs do the comparison in the opposite way that makes sense
|
||||
* for this API. For example, if the compare function is GL_GREATER then the
|
||||
* stencil test will pass if the reference value is greater than the value
|
||||
* in the stencil buffer. With our API it's more intuitive to assume that
|
||||
* setStencilTest(COMPARE_GREATER, 4) will make it pass if the stencil
|
||||
* buffer has a value greater than 4.
|
||||
**/
|
||||
|
||||
switch (compare)
|
||||
{
|
||||
case COMPARE_LESS:
|
||||
glcompare = GL_GREATER;
|
||||
break;
|
||||
case COMPARE_LEQUAL:
|
||||
glcompare = GL_GEQUAL;
|
||||
break;
|
||||
case COMPARE_EQUAL:
|
||||
default:
|
||||
glcompare = GL_EQUAL;
|
||||
break;
|
||||
case COMPARE_GEQUAL:
|
||||
glcompare = GL_LEQUAL;
|
||||
break;
|
||||
case COMPARE_GREATER:
|
||||
glcompare = GL_LESS;
|
||||
break;
|
||||
case COMPARE_NOTEQUAL:
|
||||
glcompare = GL_NOTEQUAL;
|
||||
break;
|
||||
case COMPARE_ALWAYS:
|
||||
glcompare = GL_ALWAYS;
|
||||
break;
|
||||
}
|
||||
GLenum glcompare = OpenGL::getGLCompareMode(getReversedCompareMode(compare));
|
||||
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
glStencilFunc(glcompare, value, 0xFFFFFFFF);
|
||||
|
||||
@@ -380,6 +380,8 @@ void Image::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap,
|
||||
if (w != oldd->getWidth() || h != oldd->getHeight())
|
||||
throw love::Exception("Dimensions must match the texture's dimensions for the specified mipmap level.");
|
||||
|
||||
Graphics::flushStreamDrawsGlobal();
|
||||
|
||||
d->retain();
|
||||
oldd->release();
|
||||
|
||||
@@ -397,6 +399,8 @@ void Image::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap,
|
||||
|
||||
void Image::replacePixels(const void *data, size_t size, const Rect &rect, int slice, int mipmap, bool reloadmipmaps)
|
||||
{
|
||||
Graphics::flushStreamDrawsGlobal();
|
||||
|
||||
OpenGL::TempDebugGroup debuggroup("Image replace pixels");
|
||||
|
||||
gl.bindTextureToUnit(this, 0, false);
|
||||
@@ -422,6 +426,8 @@ void Image::setFilter(const Texture::Filter &f)
|
||||
throw love::Exception("Invalid texture filter.");
|
||||
}
|
||||
|
||||
Graphics::flushStreamDrawsGlobal();
|
||||
|
||||
filter = f;
|
||||
|
||||
if (!OpenGL::hasTextureFilteringSupport(getPixelFormat()))
|
||||
@@ -445,6 +451,8 @@ void Image::setFilter(const Texture::Filter &f)
|
||||
|
||||
bool Image::setWrap(const Texture::Wrap &w)
|
||||
{
|
||||
Graphics::flushStreamDrawsGlobal();
|
||||
|
||||
bool success = true;
|
||||
bool forceclamp = texType == TEXTURE_CUBE;
|
||||
wrap = w;
|
||||
@@ -483,6 +491,8 @@ bool Image::setMipmapSharpness(float sharpness)
|
||||
if (!GLAD_VERSION_1_4)
|
||||
return false;
|
||||
|
||||
Graphics::flushStreamDrawsGlobal();
|
||||
|
||||
// LOD bias has the range (-maxbias, maxbias)
|
||||
mipmapSharpness = std::min(std::max(sharpness, -maxMipmapSharpness + 0.01f), maxMipmapSharpness - 0.01f);
|
||||
|
||||
|
||||
@@ -987,6 +987,29 @@ GLint OpenGL::getGLWrapMode(Texture::WrapMode wmode)
|
||||
|
||||
}
|
||||
|
||||
GLint OpenGL::getGLCompareMode(CompareMode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case COMPARE_LESS:
|
||||
return GL_LESS;
|
||||
case COMPARE_LEQUAL:
|
||||
return GL_LEQUAL;
|
||||
case COMPARE_EQUAL:
|
||||
return GL_EQUAL;
|
||||
case COMPARE_GEQUAL:
|
||||
return GL_GEQUAL;
|
||||
case COMPARE_GREATER:
|
||||
return GL_GREATER;
|
||||
case COMPARE_NOTEQUAL:
|
||||
return GL_NOTEQUAL;
|
||||
case COMPARE_ALWAYS:
|
||||
return GL_ALWAYS;
|
||||
default:
|
||||
return GL_NEVER;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGL::setTextureWrap(TextureType target, const graphics::Texture::Wrap &w)
|
||||
{
|
||||
glTexParameteri(getGLTextureType(target), GL_TEXTURE_WRAP_S, getGLWrapMode(w.s));
|
||||
@@ -1108,6 +1131,13 @@ bool OpenGL::isInstancingSupported() const
|
||||
|| GLAD_ARB_instanced_arrays || GLAD_EXT_instanced_arrays || GLAD_ANGLE_instanced_arrays;
|
||||
}
|
||||
|
||||
bool OpenGL::isDepthCompareSampleSupported() const
|
||||
{
|
||||
// Our official API only supports this in GLSL3 shaders, but unofficially
|
||||
// the requirements are more lax.
|
||||
return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_shadow_samplers;
|
||||
}
|
||||
|
||||
int OpenGL::getMax2DTextureSize() const
|
||||
{
|
||||
return std::max(max2DTextureSize, 1);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "graphics/Color.h"
|
||||
#include "graphics/Texture.h"
|
||||
#include "graphics/vertex.h"
|
||||
#include "graphics/depthstencil.h"
|
||||
#include "common/Matrix.h"
|
||||
|
||||
// GLAD
|
||||
@@ -326,6 +327,7 @@ public:
|
||||
bool isClampZeroTextureWrapSupported() const;
|
||||
bool isPixelShaderHighpSupported() const;
|
||||
bool isInstancingSupported() const;
|
||||
bool isDepthCompareSampleSupported() const;
|
||||
|
||||
/**
|
||||
* Returns the maximum supported width or height of a texture.
|
||||
@@ -379,6 +381,7 @@ public:
|
||||
static GLenum getGLBufferUsage(vertex::Usage usage);
|
||||
static GLenum getGLTextureType(TextureType type);
|
||||
static GLint getGLWrapMode(Texture::WrapMode wmode);
|
||||
static GLint getGLCompareMode(CompareMode mode);
|
||||
|
||||
static TextureFormat convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB);
|
||||
static bool isTexStorageSupported();
|
||||
|
||||
@@ -173,6 +173,7 @@ void Shader::mapActiveUniforms()
|
||||
u.location = glGetUniformLocation(program, u.name.c_str());
|
||||
u.baseType = getUniformBaseType(gltype);
|
||||
u.textureType = getUniformTextureType(gltype);
|
||||
u.isDepthSampler = isDepthTextureType(gltype);
|
||||
|
||||
if (u.baseType == UNIFORM_MATRIX)
|
||||
u.matrix = getMatrixSize(gltype);
|
||||
@@ -675,22 +676,51 @@ void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count
|
||||
// Bind the textures to the texture units.
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (textures[i] != nullptr)
|
||||
{
|
||||
if (textures[i]->getTextureType() != info->textureType || !textures[i]->isReadable())
|
||||
continue;
|
||||
Texture *tex = textures[i];
|
||||
|
||||
textures[i]->retain();
|
||||
if (tex != nullptr)
|
||||
{
|
||||
if (!tex->isReadable())
|
||||
{
|
||||
if (internalUpdate)
|
||||
continue;
|
||||
else
|
||||
throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader.");
|
||||
}
|
||||
else if (info->isDepthSampler != tex->getDepthSampleMode().hasValue)
|
||||
{
|
||||
if (internalUpdate)
|
||||
continue;
|
||||
else if (info->isDepthSampler)
|
||||
throw love::Exception("Depth comparison samplers in shaders can only be used with depth textures which have depth comparison set.");
|
||||
else
|
||||
throw love::Exception("Depth textures which have depth comparison set can only be used with depth/shadow samplers in shaders.");
|
||||
}
|
||||
else if (tex->getTextureType() != info->textureType)
|
||||
{
|
||||
if (internalUpdate)
|
||||
continue;
|
||||
else
|
||||
{
|
||||
const char *textypestr = "unknown";
|
||||
const char *shadertextypestr = "unknown";
|
||||
Texture::getConstant(tex->getTextureType(), textypestr);
|
||||
Texture::getConstant(info->textureType, shadertextypestr);
|
||||
throw love::Exception("Texture's type (%s) must match the type of %s (%s).", textypestr, info->name.c_str(), shadertextypestr);
|
||||
}
|
||||
}
|
||||
|
||||
tex->retain();
|
||||
}
|
||||
|
||||
if (info->textures[i] != nullptr)
|
||||
info->textures[i]->release();
|
||||
|
||||
info->textures[i] = textures[i];
|
||||
info->textures[i] = tex;
|
||||
|
||||
GLuint gltex = 0;
|
||||
if (textures[i] != nullptr)
|
||||
gltex = (GLuint) textures[i]->getHandle();
|
||||
gltex = (GLuint) tex->getHandle();
|
||||
else
|
||||
gltex = gl.getDefaultTexture(info->textureType);
|
||||
|
||||
@@ -707,11 +737,7 @@ void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count
|
||||
void Shader::flushStreamDraws() const
|
||||
{
|
||||
if (current == this)
|
||||
{
|
||||
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
|
||||
if (gfx != nullptr)
|
||||
gfx->flushStreamDraws();
|
||||
}
|
||||
Graphics::flushStreamDrawsGlobal();
|
||||
}
|
||||
|
||||
bool Shader::hasUniform(const std::string &name) const
|
||||
@@ -1035,7 +1061,7 @@ TextureType Shader::getUniformTextureType(GLenum type) const
|
||||
// 1D-typed textures are not supported.
|
||||
return TEXTURE_MAX_ENUM;
|
||||
case GL_SAMPLER_2D:
|
||||
//case GL_SAMPLER_2D_SHADOW:
|
||||
case GL_SAMPLER_2D_SHADOW:
|
||||
return TEXTURE_2D;
|
||||
case GL_SAMPLER_2D_MULTISAMPLE:
|
||||
case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
|
||||
@@ -1046,12 +1072,12 @@ TextureType Shader::getUniformTextureType(GLenum type) const
|
||||
// Rectangle textures are not supported.
|
||||
return TEXTURE_MAX_ENUM;
|
||||
case GL_SAMPLER_2D_ARRAY:
|
||||
//case GL_SAMPLER_2D_ARRAY_SHADOW:
|
||||
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:
|
||||
case GL_SAMPLER_CUBE_SHADOW:
|
||||
return TEXTURE_CUBE;
|
||||
case GL_SAMPLER_CUBE_MAP_ARRAY:
|
||||
case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
|
||||
@@ -1062,6 +1088,22 @@ TextureType Shader::getUniformTextureType(GLenum type) const
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
} // opengl
|
||||
} // graphics
|
||||
} // love
|
||||
|
||||
@@ -94,6 +94,7 @@ private:
|
||||
MatrixSize getMatrixSize(GLenum type) const;
|
||||
UniformType getUniformBaseType(GLenum type) const;
|
||||
TextureType getUniformTextureType(GLenum type) const;
|
||||
bool isDepthTextureType(GLenum type) const;
|
||||
|
||||
GLuint compileCode(ShaderStage stage, const std::string &code);
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ void Text::draw(Graphics *gfx, const Matrix4 &m)
|
||||
return;
|
||||
|
||||
if (Shader::current)
|
||||
Shader::current->checkMainTextureType(TEXTURE_2D);
|
||||
Shader::current->checkMainTextureType(TEXTURE_2D, false);
|
||||
|
||||
gfx->flushStreamDraws();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user