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
+2
View File
@@ -475,6 +475,8 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT
src/modules/graphics/Canvas.cpp
src/modules/graphics/Canvas.h
src/modules/graphics/Color.h
src/modules/graphics/depthstencil.cpp
src/modules/graphics/depthstencil.h
src/modules/graphics/Drawable.cpp
src/modules/graphics/Drawable.h
src/modules/graphics/Font.cpp
@@ -1132,6 +1132,8 @@
FAF140DB1E20934C00F898D2 /* InitializeDll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */; };
FAF140DC1E20934C00F898D2 /* InitializeDll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */; };
FAF140DD1E20934C00F898D2 /* InitializeDll.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF1403C1E20934C00F898D2 /* InitializeDll.h */; };
FAF1889F1E9DBC4B008C1479 /* depthstencil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1889E1E9DBC4B008C1479 /* depthstencil.cpp */; };
FAF188A01E9DBC4B008C1479 /* depthstencil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1889E1E9DBC4B008C1479 /* depthstencil.cpp */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
@@ -1937,6 +1939,8 @@
FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitializeDll.cpp; sourceTree = "<group>"; };
FAF1403C1E20934C00F898D2 /* InitializeDll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeDll.h; sourceTree = "<group>"; };
FAF1889C1E9DA834008C1479 /* Optional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Optional.h; sourceTree = "<group>"; };
FAF1889D1E9DBBC8008C1479 /* depthstencil.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = depthstencil.h; sourceTree = "<group>"; };
FAF1889E1E9DBC4B008C1479 /* depthstencil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = depthstencil.cpp; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -2663,6 +2667,8 @@
FA1BA0A51E16F20600AA2803 /* Canvas.cpp */,
FA1BA0A61E16F20600AA2803 /* Canvas.h */,
FA0B7B881A95902C000E1D17 /* Color.h */,
FAF1889E1E9DBC4B008C1479 /* depthstencil.cpp */,
FAF1889D1E9DBBC8008C1479 /* depthstencil.h */,
FA9D8DDC1DEF842A002CD881 /* Drawable.cpp */,
FA0B7B891A95902C000E1D17 /* Drawable.h */,
FA1BA09B1E16CFCE00AA2803 /* Font.cpp */,
@@ -4185,6 +4191,7 @@
FA0B7DDD1A95902C000E1D17 /* wrap_BezierCurve.cpp in Sources */,
FA0B7A2A1A958EA3000E1D17 /* b2BroadPhase.cpp in Sources */,
FA0B7A811A958EA3000E1D17 /* b2EdgeAndCircleContact.cpp in Sources */,
FAF188A01E9DBC4B008C1479 /* depthstencil.cpp in Sources */,
FA0B7D071A95902C000E1D17 /* wrap_File.cpp in Sources */,
FAD19A181DFF8CA200D5398A /* ImageDataBase.cpp in Sources */,
FA0B7AD01A958EA3000E1D17 /* peer.c in Sources */,
@@ -4545,6 +4552,7 @@
FA0B7DDC1A95902C000E1D17 /* wrap_BezierCurve.cpp in Sources */,
FA0B7A951A958EA3000E1D17 /* b2Joint.cpp in Sources */,
FA0B7D061A95902C000E1D17 /* wrap_File.cpp in Sources */,
FAF1889F1E9DBC4B008C1479 /* depthstencil.cpp in Sources */,
FA0B7A4E1A958EA3000E1D17 /* b2Draw.cpp in Sources */,
FAD19A171DFF8CA200D5398A /* ImageDataBase.cpp in Sources */,
FA27B3C01B4985BF008A9DCE /* wrap_VideoStream.cpp in Sources */,
+6 -3
View File
@@ -23,7 +23,7 @@
namespace love
{
// Currently only meant for simple types.
// Currently only meant for simple and small types.
template <typename T>
struct Optional
{
@@ -40,8 +40,11 @@ struct Optional
, value(val)
{}
private:
void set(T val)
{
hasValue = true;
value = val;
}
};
typedef Optional<bool> OptionalBool;
+6
View File
@@ -125,6 +125,12 @@ bool isPixelFormatDepthStencil(PixelFormat format)
return iformat >= (int) PIXELFORMAT_STENCIL8 && iformat <= (int) PIXELFORMAT_DEPTH32F_STENCIL8;
}
bool isPixelFormatDepth(PixelFormat format)
{
int iformat = (int) format;
return iformat >= (int) PIXELFORMAT_DEPTH16 && iformat <= (int) PIXELFORMAT_DEPTH32F_STENCIL8;
}
size_t getPixelFormatSize(PixelFormat format)
{
switch (format)
+6 -1
View File
@@ -115,10 +115,15 @@ bool getConstant(const char *in, PixelFormat &out);
bool isPixelFormatCompressed(PixelFormat format);
/**
* Gets whether the specified pixel format is a depth/stencil type.
* Gets whether the specified pixel format is a depth or stencil type.
**/
bool isPixelFormatDepthStencil(PixelFormat format);
/**
* Gets whether the specified pixel format is a depth type.
**/
bool isPixelFormatDepth(PixelFormat format);
/**
* Gets the size in bytes of the specified pixel format.
* NOTE: Currently returns 0 for compressed formats.
+10 -45
View File
@@ -589,6 +589,9 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest &
StreamBufferState &state = streamBufferState;
if (state.vertexCount == 0 && Shader::current != nullptr && req.texture != nullptr)
Shader::current->checkMainTexture(req.texture);
bool shouldflush = false;
bool shouldresize = false;
@@ -706,6 +709,13 @@ Graphics::StreamVertexData Graphics::requestStreamDraw(const StreamDrawRequest &
return d;
}
void Graphics::flushStreamDrawsGlobal()
{
Graphics *instance = getInstance<Graphics>(M_GRAPHICS);
if (instance != nullptr)
instance->flushStreamDraws();
}
/**
* Drawing
**/
@@ -1266,26 +1276,6 @@ bool Graphics::getConstant(LineJoin in, const char *&out)
return lineJoins.find(in, out);
}
bool Graphics::getConstant(const char *in, StencilAction &out)
{
return stencilActions.find(in, out);
}
bool Graphics::getConstant(StencilAction in, const char *&out)
{
return stencilActions.find(in, out);
}
bool Graphics::getConstant(const char *in, CompareMode &out)
{
return compareModes.find(in, out);
}
bool Graphics::getConstant(CompareMode in, const char *&out)
{
return compareModes.find(in, out);
}
bool Graphics::getConstant(const char *in, Feature &out)
{
return features.find(in, out);
@@ -1373,31 +1363,6 @@ StringMap<Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM>::Entry Graphics::lin
StringMap<Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM> Graphics::lineJoins(Graphics::lineJoinEntries, sizeof(Graphics::lineJoinEntries));
StringMap<Graphics::StencilAction, Graphics::STENCIL_MAX_ENUM>::Entry Graphics::stencilActionEntries[] =
{
{ "replace", STENCIL_REPLACE },
{ "increment", STENCIL_INCREMENT },
{ "decrement", STENCIL_DECREMENT },
{ "incrementwrap", STENCIL_INCREMENT_WRAP },
{ "decrementwrap", STENCIL_DECREMENT_WRAP },
{ "invert", STENCIL_INVERT },
};
StringMap<Graphics::StencilAction, Graphics::STENCIL_MAX_ENUM> Graphics::stencilActions(Graphics::stencilActionEntries, sizeof(Graphics::stencilActionEntries));
StringMap<Graphics::CompareMode, Graphics::COMPARE_MAX_ENUM>::Entry Graphics::compareModeEntries[] =
{
{ "less", COMPARE_LESS },
{ "lequal", COMPARE_LEQUAL },
{ "equal", COMPARE_EQUAL },
{ "gequal", COMPARE_GEQUAL },
{ "greater", COMPARE_GREATER },
{ "notequal", COMPARE_NOTEQUAL },
{ "always", COMPARE_ALWAYS },
};
StringMap<Graphics::CompareMode, Graphics::COMPARE_MAX_ENUM> Graphics::compareModes(Graphics::compareModeEntries, sizeof(Graphics::compareModeEntries));
StringMap<Graphics::Feature, Graphics::FEATURE_MAX_ENUM>::Entry Graphics::featureEntries[] =
{
{ "multicanvasformats", FEATURE_MULTI_CANVAS_FORMATS },
+3 -35
View File
@@ -37,6 +37,7 @@
#include "Quad.h"
#include "Mesh.h"
#include "Image.h"
#include "depthstencil.h"
#include "math/Transform.h"
#include "font/Rasterizer.h"
#include "video/VideoStream.h"
@@ -150,29 +151,6 @@ public:
LINE_JOIN_MAX_ENUM
};
enum StencilAction
{
STENCIL_REPLACE,
STENCIL_INCREMENT,
STENCIL_DECREMENT,
STENCIL_INCREMENT_WRAP,
STENCIL_DECREMENT_WRAP,
STENCIL_INVERT,
STENCIL_MAX_ENUM
};
enum CompareMode
{
COMPARE_LESS,
COMPARE_LEQUAL,
COMPARE_EQUAL,
COMPARE_GEQUAL,
COMPARE_GREATER,
COMPARE_NOTEQUAL,
COMPARE_ALWAYS,
COMPARE_MAX_ENUM
};
enum Feature
{
FEATURE_MULTI_CANVAS_FORMATS,
@@ -761,6 +739,8 @@ public:
virtual void flushStreamDraws() = 0;
StreamVertexData requestStreamDraw(const StreamDrawRequest &request);
static void flushStreamDrawsGlobal();
virtual Shader::Language getShaderLanguageTarget() const = 0;
const Shader::ShaderSource &getCurrentDefaultShaderCode() const;
@@ -793,12 +773,6 @@ public:
static bool getConstant(const char *in, LineJoin &out);
static bool getConstant(LineJoin in, const char *&out);
static bool getConstant(const char *in, StencilAction &out);
static bool getConstant(StencilAction in, const char *&out);
static bool getConstant(const char *in, CompareMode &out);
static bool getConstant(CompareMode in, const char *&out);
static bool getConstant(const char *in, Feature &out);
static bool getConstant(Feature in, const char *&out);
@@ -932,12 +906,6 @@ private:
static StringMap<LineJoin, LINE_JOIN_MAX_ENUM>::Entry lineJoinEntries[];
static StringMap<LineJoin, LINE_JOIN_MAX_ENUM> lineJoins;
static StringMap<StencilAction, STENCIL_MAX_ENUM>::Entry stencilActionEntries[];
static StringMap<StencilAction, STENCIL_MAX_ENUM> stencilActions;
static StringMap<CompareMode, COMPARE_MAX_ENUM>::Entry compareModeEntries[];
static StringMap<CompareMode, COMPARE_MAX_ENUM> compareModes;
static StringMap<Feature, FEATURE_MAX_ENUM>::Entry featureEntries[];
static StringMap<Feature, FEATURE_MAX_ENUM> features;
+16 -5
View File
@@ -192,11 +192,14 @@ TextureType Shader::getMainTextureType() const
return info != nullptr ? info->textureType : TEXTURE_MAX_ENUM;
}
void Shader::checkMainTextureType(TextureType textype) const
void Shader::checkMainTextureType(TextureType textype, bool isDepthSampler) const
{
const UniformInfo *info = getUniformInfo(BUILTIN_TEXTURE_MAIN);
if (info != nullptr && info->textureType != TEXTURE_MAX_ENUM && info->textureType != textype)
if (info == nullptr)
return;
if (info->textureType != TEXTURE_MAX_ENUM && info->textureType != textype)
{
const char *textypestr = "unknown";
const char *shadertextypestr = "unknown";
@@ -204,14 +207,22 @@ void Shader::checkMainTextureType(TextureType textype) const
Texture::getConstant(info->textureType, shadertextypestr);
throw love::Exception("Texture's type (%s) must match the type of the shader's main texture type (%s).", textypestr, shadertextypestr);
}
if (info->isDepthSampler != isDepthSampler)
{
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.");
}
}
void Shader::checkMainTexture(Texture *texture) const
void Shader::checkMainTexture(Texture *tex) const
{
if (!texture->isReadable())
if (!tex->isReadable())
throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader.");
checkMainTextureType(texture->getTextureType());
checkMainTextureType(tex->getTextureType(), tex->getDepthSampleMode().hasValue);
}
bool Shader::validate(Graphics *gfx, bool gles, const ShaderSource &source, bool checkWithDefaults, std::string &err)
+2 -2
View File
@@ -128,7 +128,7 @@ public:
UniformType baseType;
TextureType textureType;
bool isDepthTexture;
bool isDepthSampler;
std::string name;
union
@@ -190,7 +190,7 @@ public:
virtual void setVideoTextures(Texture *ytexture, Texture *cbtexture, Texture *crtexture) = 0;
TextureType getMainTextureType() const;
void checkMainTextureType(TextureType textype) const;
void checkMainTextureType(TextureType textype, bool isDepthSampler) const;
void checkMainTexture(Texture *texture) const;
virtual ptrdiff_t getHandle() const = 0;
+11
View File
@@ -230,6 +230,17 @@ float Texture::getMipmapSharpness() const
return mipmapSharpness;
}
void Texture::setDepthSampleMode(Optional<CompareMode> mode)
{
if (mode.hasValue && (!readable || !isPixelFormatDepthStencil(format)))
throw love::Exception("Only readable depth textures can have a depth sample compare mode.");
}
Optional<CompareMode> Texture::getDepthSampleMode() const
{
return depthCompareMode;
}
Quad *Texture::getQuad() const
{
return quad;
+7
View File
@@ -26,9 +26,11 @@
#include "common/math.h"
#include "common/pixelformat.h"
#include "common/Exception.h"
#include "common/Optional.h"
#include "Drawable.h"
#include "Quad.h"
#include "vertex.h"
#include "depthstencil.h"
// C
#include <stddef.h>
@@ -143,6 +145,9 @@ public:
virtual bool setMipmapSharpness(float sharpness) = 0;
float getMipmapSharpness() const;
virtual void setDepthSampleMode(Optional<CompareMode> mode = Optional<CompareMode>());
Optional<CompareMode> getDepthSampleMode() const;
Quad *getQuad() const;
virtual ptrdiff_t getHandle() const = 0;
@@ -185,6 +190,8 @@ protected:
float mipmapSharpness;
Optional<CompareMode> depthCompareMode;
StrongRef<Quad> quad;
private:
+99
View File
@@ -0,0 +1,99 @@
/**
* Copyright (c) 2006-2017 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
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "depthstencil.h"
#include "common/StringMap.h"
namespace love
{
namespace graphics
{
CompareMode getReversedCompareMode(CompareMode mode)
{
switch (mode)
{
case COMPARE_LESS:
return COMPARE_GREATER;
case COMPARE_LEQUAL:
return COMPARE_GEQUAL;
case COMPARE_EQUAL:
return COMPARE_EQUAL;
case COMPARE_GEQUAL:
return COMPARE_LEQUAL;
case COMPARE_GREATER:
return COMPARE_LESS;
case COMPARE_NOTEQUAL:
return COMPARE_NOTEQUAL;
case COMPARE_ALWAYS:
return COMPARE_ALWAYS;
case COMPARE_MAX_ENUM:
default:
return COMPARE_MAX_ENUM;
}
}
static StringMap<StencilAction, STENCIL_MAX_ENUM>::Entry stencilActionEntries[] =
{
{ "replace", STENCIL_REPLACE },
{ "increment", STENCIL_INCREMENT },
{ "decrement", STENCIL_DECREMENT },
{ "incrementwrap", STENCIL_INCREMENT_WRAP },
{ "decrementwrap", STENCIL_DECREMENT_WRAP },
{ "invert", STENCIL_INVERT },
};
static StringMap<StencilAction, STENCIL_MAX_ENUM> stencilActions(stencilActionEntries, sizeof(stencilActionEntries));
static StringMap<CompareMode, COMPARE_MAX_ENUM>::Entry compareModeEntries[] =
{
{ "less", COMPARE_LESS },
{ "lequal", COMPARE_LEQUAL },
{ "equal", COMPARE_EQUAL },
{ "gequal", COMPARE_GEQUAL },
{ "greater", COMPARE_GREATER },
{ "notequal", COMPARE_NOTEQUAL },
{ "always", COMPARE_ALWAYS },
};
static StringMap<CompareMode, COMPARE_MAX_ENUM> compareModes(compareModeEntries, sizeof(compareModeEntries));
bool getConstant(const char *in, StencilAction &out)
{
return stencilActions.find(in, out);
}
bool getConstant(StencilAction in, const char *&out)
{
return stencilActions.find(in, out);
}
bool getConstant(const char *in, CompareMode &out)
{
return compareModes.find(in, out);
}
bool getConstant(CompareMode in, const char *&out)
{
return compareModes.find(in, out);
}
} // graphics
} // love
+68
View File
@@ -0,0 +1,68 @@
/**
* Copyright (c) 2006-2017 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
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#pragma once
namespace love
{
namespace graphics
{
enum StencilAction
{
STENCIL_REPLACE,
STENCIL_INCREMENT,
STENCIL_DECREMENT,
STENCIL_INCREMENT_WRAP,
STENCIL_DECREMENT_WRAP,
STENCIL_INVERT,
STENCIL_MAX_ENUM
};
enum CompareMode
{
COMPARE_LESS,
COMPARE_LEQUAL,
COMPARE_EQUAL,
COMPARE_GEQUAL,
COMPARE_GREATER,
COMPARE_NOTEQUAL,
COMPARE_ALWAYS,
COMPARE_MAX_ENUM
};
/**
* GPU APIs do the comparison in the opposite way of what makes sense for some
* of love's APIs. For example in OpenGL 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 stencil 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.
**/
CompareMode getReversedCompareMode(CompareMode mode);
bool getConstant(const char *in, StencilAction &out);
bool getConstant(StencilAction in, const char *&out);
bool getConstant(const char *in, CompareMode &out);
bool getConstant(CompareMode in, const char *&out);
} // graphics
} // love
+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();
+6 -6
View File
@@ -489,12 +489,12 @@ int w_stencil(lua_State *L)
{
luaL_checktype(L, 1, LUA_TFUNCTION);
Graphics::StencilAction action = Graphics::STENCIL_REPLACE;
StencilAction action = STENCIL_REPLACE;
if (!lua_isnoneornil(L, 2))
{
const char *actionstr = luaL_checkstring(L, 2);
if (!Graphics::getConstant(actionstr, action))
if (!getConstant(actionstr, action))
return luaL_error(L, "Invalid stencil draw action: %s", actionstr);
}
@@ -522,13 +522,13 @@ int w_stencil(lua_State *L)
int w_setStencilTest(lua_State *L)
{
// COMPARE_ALWAYS effectively disables stencil testing.
Graphics::CompareMode compare = Graphics::COMPARE_ALWAYS;
CompareMode compare = COMPARE_ALWAYS;
int comparevalue = 0;
if (!lua_isnoneornil(L, 1))
{
const char *comparestr = luaL_checkstring(L, 1);
if (!Graphics::getConstant(comparestr, compare))
if (!getConstant(comparestr, compare))
return luaL_error(L, "Invalid compare mode: %s", comparestr);
comparevalue = (int) luaL_checknumber(L, 2);
@@ -540,13 +540,13 @@ int w_setStencilTest(lua_State *L)
int w_getStencilTest(lua_State *L)
{
Graphics::CompareMode compare = Graphics::COMPARE_ALWAYS;
CompareMode compare = COMPARE_ALWAYS;
int comparevalue = 1;
instance()->getStencilTest(compare, comparevalue);
const char *comparestr;
if (!Graphics::getConstant(compare, comparestr))
if (!getConstant(compare, comparestr))
return luaL_error(L, "Unknown compare mode.");
lua_pushstring(L, comparestr);
+10
View File
@@ -50,6 +50,11 @@ GLSL.SYNTAX = [[
#define ArrayImage sampler2DArray
#define CubeImage samplerCube
#define VolumeImage sampler3D
#if __VERSION__ >= 300 && !defined(LOVE_GLSL1_ON_GLSL3)
#define DepthImage sampler2DShadow
#define DepthArrayImage sampler2DArrayShadow
#define DepthCubeImage samplerCubeShadow
#endif
#define extern uniform
#ifdef GL_EXT_texture_array
#extension GL_EXT_texture_array : enable
@@ -78,6 +83,11 @@ GLSL.FUNCTIONS = [[
#if __VERSION__ >= 300 || defined(GL_OES_texture_3D)
precision lowp sampler3D;
#endif
#if __VERSION__ >= 300
precision lowp sampler2DShadow;
precision lowp samplerCubeShadow;
precision lowp sampler2DArrayShadow;
#endif
#endif
#if __VERSION__ >= 130 && !defined(LOVE_GLSL1_ON_GLSL3)
+38
View File
@@ -244,6 +244,42 @@ int w_Texture_isReadable(lua_State *L)
return 1;
}
int w_Texture_setDepthSampleMode(lua_State *L)
{
Texture *t = luax_checktexture(L, 1);
Optional<CompareMode> mode;
if (!lua_isnoneornil(L, 2))
{
const char *str = luaL_checkstring(L, 2);
mode.hasValue = true;
if (!getConstant(str, mode.value))
return luaL_error(L, "Invalid compare mode: %s", str);
}
luax_catchexcept(L, [&]() { t->setDepthSampleMode(mode); });
return 0;
}
int w_Texture_getDepthSampleMode(lua_State *L)
{
Texture *t = luax_checktexture(L, 1);
Optional<CompareMode> mode = t->getDepthSampleMode();
if (mode.hasValue)
{
const char *str = nullptr;
if (!getConstant(mode.value, str))
return luaL_error(L, "Unknown compare mode.");
lua_pushstring(L, str);
}
else
lua_pushnil(L);
return 1;
}
const luaL_Reg w_Texture_functions[] =
{
{ "getTextureType", w_Texture_getTextureType },
@@ -265,6 +301,8 @@ const luaL_Reg w_Texture_functions[] =
{ "getWrap", w_Texture_getWrap },
{ "getFormat", w_Texture_getFormat },
{ "isReadable", w_Texture_isReadable },
{ "getDepthSampleMode", w_Texture_getDepthSampleMode },
{ "setDepthSampleMode", w_Texture_setDepthSampleMode },
{ 0, 0 }
};