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:
Alex Szpakowski
2017-04-12 20:26:06 -03:00
parent 0001b4695e
commit a0ef2ac28b
25 changed files with 444 additions and 151 deletions
+41
View File
@@ -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;
+1
View File
@@ -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;
+2 -38
View File
@@ -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);
+10
View File
@@ -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);
+30
View File
@@ -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);
+3
View File
@@ -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();
+57 -15
View File
@@ -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
+1
View File
@@ -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);
+1 -1
View File
@@ -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();