Move some Canvas code to Texture, devirtualize Texture::draw.

This commit is contained in:
Alex Szpakowski
2020-02-03 19:02:58 -04:00
parent f9248d478c
commit b46b3ed552
19 changed files with 136 additions and 128 deletions
+14
View File
@@ -137,6 +137,20 @@ bool isPixelFormatStencil(PixelFormat format)
return format == PIXELFORMAT_STENCIL8 || format == PIXELFORMAT_DEPTH24_UNORM_STENCIL8 || format == PIXELFORMAT_DEPTH32_FLOAT_STENCIL8; return format == PIXELFORMAT_STENCIL8 || format == PIXELFORMAT_DEPTH24_UNORM_STENCIL8 || format == PIXELFORMAT_DEPTH32_FLOAT_STENCIL8;
} }
PixelFormat getSRGBPixelFormat(PixelFormat format)
{
if (format == PIXELFORMAT_RGBA8_UNORM)
return PIXELFORMAT_sRGBA8_UNORM;
return format;
}
PixelFormat getLinearPixelFormat(PixelFormat format)
{
if (format == PIXELFORMAT_sRGBA8_UNORM)
return PIXELFORMAT_RGBA8_UNORM;
return format;
}
size_t getPixelFormatSize(PixelFormat format) size_t getPixelFormatSize(PixelFormat format)
{ {
switch (format) switch (format)
+10
View File
@@ -132,6 +132,16 @@ bool isPixelFormatDepth(PixelFormat format);
**/ **/
bool isPixelFormatStencil(PixelFormat format); bool isPixelFormatStencil(PixelFormat format);
/**
* Gets the sRGB version of a linear pixel format, if applicable.
**/
PixelFormat getSRGBPixelFormat(PixelFormat format);
/**
* Gets the linear version of a sRGB pixel format, if applicable.
**/
PixelFormat getLinearPixelFormat(PixelFormat format);
/** /**
* Gets the size in bytes of the specified pixel format. * Gets the size in bytes of the specified pixel format.
* NOTE: Currently returns 0 for compressed formats. * NOTE: Currently returns 0 for compressed formats.
+6 -25
View File
@@ -27,13 +27,15 @@ namespace graphics
{ {
love::Type Canvas::type("Canvas", &Texture::type); love::Type Canvas::type("Canvas", &Texture::type);
int Canvas::canvasCount = 0;
Canvas::Canvas(const Settings &settings) Canvas::Canvas(const Settings &settings)
: Texture(settings.type) : Texture(settings.type)
{ {
this->settings = settings; this->settings = settings;
renderTarget = true;
sRGB = false;
width = settings.width; width = settings.width;
height = settings.height; height = settings.height;
pixelWidth = (int) ((width * settings.dpiScale) + 0.5); pixelWidth = (int) ((width * settings.dpiScale) + 0.5);
@@ -69,7 +71,7 @@ Canvas::Canvas(const Settings &settings)
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS); auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
const Graphics::Capabilities &caps = gfx->getCapabilities(); const Graphics::Capabilities &caps = gfx->getCapabilities();
if (!gfx->isPixelFormatSupported(format, true, readable, false)) if (!gfx->isPixelFormatSupported(format, renderTarget, readable, sRGB))
{ {
const char *fstr = "rgba8"; const char *fstr = "rgba8";
const char *readablestr = ""; const char *readablestr = "";
@@ -93,13 +95,10 @@ Canvas::Canvas(const Settings &settings)
} }
validateDimensions(true); validateDimensions(true);
canvasCount++;
} }
Canvas::~Canvas() Canvas::~Canvas()
{ {
canvasCount--;
} }
Canvas::MipmapMode Canvas::getMipmapMode() const Canvas::MipmapMode Canvas::getMipmapMode() const
@@ -131,12 +130,10 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *module, int sli
} }
Graphics *gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS); Graphics *gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
if (gfx != nullptr && gfx->isCanvasActive(this)) if (gfx != nullptr && gfx->isRenderTargetActive(this))
throw love::Exception("Canvas:newImageData cannot be called while that Canvas is currently active."); throw love::Exception("Canvas:newImageData cannot be called while that Canvas is currently active.");
PixelFormat dataformat = getPixelFormat(); PixelFormat dataformat = getLinearPixelFormat(getPixelFormat());
if (dataformat == PIXELFORMAT_sRGBA8_UNORM)
dataformat = PIXELFORMAT_RGBA8_UNORM;
if (!image::ImageData::validPixelFormat(dataformat)) if (!image::ImageData::validPixelFormat(dataformat))
{ {
@@ -148,22 +145,6 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *module, int sli
return module->newImageData(r.w, r.h, dataformat); return module->newImageData(r.w, r.h, dataformat);
} }
void Canvas::draw(Graphics *gfx, Quad *q, const Matrix4 &t)
{
if (gfx->isCanvasActive(this))
throw love::Exception("Cannot render a Canvas to itself!");
Texture::draw(gfx, q, t);
}
void Canvas::drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m)
{
if (gfx->isCanvasActive(this, layer))
throw love::Exception("Cannot render a Canvas to itself!");
Texture::drawLayer(gfx, layer, quad, m);
}
bool Canvas::getConstant(const char *in, MipmapMode &out) bool Canvas::getConstant(const char *in, MipmapMode &out)
{ {
return mipmapModes.find(in, out); return mipmapModes.find(in, out);
-6
View File
@@ -81,16 +81,10 @@ public:
int getRequestedMSAA() const; int getRequestedMSAA() const;
virtual love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect); virtual love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect);
virtual void generateMipmaps() = 0;
virtual int getMSAA() const = 0; virtual int getMSAA() const = 0;
virtual ptrdiff_t getRenderTargetHandle() const = 0; virtual ptrdiff_t getRenderTargetHandle() const = 0;
void draw(Graphics *gfx, Quad *q, const Matrix4 &t) override;
void drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &t) override;
static int canvasCount;
static bool getConstant(const char *in, MipmapMode &out); static bool getConstant(const char *in, MipmapMode &out);
static bool getConstant(MipmapMode in, const char *&out); static bool getConstant(MipmapMode in, const char *&out);
static std::vector<std::string> getConstants(MipmapMode); static std::vector<std::string> getConstants(MipmapMode);
+7 -8
View File
@@ -761,33 +761,33 @@ bool Graphics::isCanvasActive() const
return !rts.colors.empty() || rts.depthStencil.canvas != nullptr; return !rts.colors.empty() || rts.depthStencil.canvas != nullptr;
} }
bool Graphics::isCanvasActive(love::graphics::Canvas *canvas) const bool Graphics::isRenderTargetActive(Texture *texture) const
{ {
const auto &rts = states.back().renderTargets; const auto &rts = states.back().renderTargets;
for (const auto &rt : rts.colors) for (const auto &rt : rts.colors)
{ {
if (rt.canvas.get() == canvas) if (rt.canvas.get() == texture)
return true; return true;
} }
if (rts.depthStencil.canvas.get() == canvas) if (rts.depthStencil.canvas.get() == texture)
return true; return true;
return false; return false;
} }
bool Graphics::isCanvasActive(Canvas *canvas, int slice) const bool Graphics::isRenderTargetActive(Texture *texture, int slice) const
{ {
const auto &rts = states.back().renderTargets; const auto &rts = states.back().renderTargets;
for (const auto &rt : rts.colors) for (const auto &rt : rts.colors)
{ {
if (rt.canvas.get() == canvas && rt.slice == slice) if (rt.canvas.get() == texture && rt.slice == slice)
return true; return true;
} }
if (rts.depthStencil.canvas.get() == canvas && rts.depthStencil.slice == slice) if (rts.depthStencil.canvas.get() == texture && rts.depthStencil.slice == slice)
return true; return true;
return false; return false;
@@ -1593,8 +1593,7 @@ Graphics::Stats Graphics::getStats() const
stats.canvasSwitches = canvasSwitchCount; stats.canvasSwitches = canvasSwitchCount;
stats.drawCallsBatched = drawCallsBatched; stats.drawCallsBatched = drawCallsBatched;
stats.canvases = Canvas::canvasCount; stats.textures = Texture::textureCount;
stats.images = Image::imageCount;
stats.fonts = Font::fontCount; stats.fonts = Font::fontCount;
stats.textureMemory = Texture::totalGraphicsMemory; stats.textureMemory = Texture::totalGraphicsMemory;
+4 -5
View File
@@ -202,8 +202,7 @@ public:
int drawCallsBatched; int drawCallsBatched;
int canvasSwitches; int canvasSwitches;
int shaderSwitches; int shaderSwitches;
int canvases; int textures;
int images;
int fonts; int fonts;
int64 textureMemory; int64 textureMemory;
}; };
@@ -551,8 +550,8 @@ public:
RenderTargets getCanvas() const; RenderTargets getCanvas() const;
bool isCanvasActive() const; bool isCanvasActive() const;
bool isCanvasActive(Canvas *canvas) const; bool isRenderTargetActive(Texture *texture) const;
bool isCanvasActive(Canvas *canvas, int slice) const; bool isRenderTargetActive(Texture *texture, int slice) const;
/** /**
* Scissor defines a box such that everything outside that box is discarded * Scissor defines a box such that everything outside that box is discarded
@@ -781,7 +780,7 @@ public:
/** /**
* Converts PIXELFORMAT_NORMAL and PIXELFORMAT_HDR into a real format. * Converts PIXELFORMAT_NORMAL and PIXELFORMAT_HDR into a real format.
**/ **/
virtual PixelFormat getSizedFormat(PixelFormat format) const = 0; virtual PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable, bool sRGB) const = 0;
/** /**
* Gets whether the specified pixel format is supported. * Gets whether the specified pixel format is supported.
+3 -17
View File
@@ -31,15 +31,14 @@ namespace graphics
love::Type Image::type("Image", &Texture::type); love::Type Image::type("Image", &Texture::type);
int Image::imageCount = 0;
Image::Image(const Slices &data, const Settings &settings, bool validatedata) Image::Image(const Slices &data, const Settings &settings, bool validatedata)
: Texture(data.getTextureType()) : Texture(data.getTextureType())
, settings(settings) , settings(settings)
, mipmapsType(settings.mipmaps ? MIPMAPS_GENERATED : MIPMAPS_NONE) , mipmapsType(settings.mipmaps ? MIPMAPS_GENERATED : MIPMAPS_NONE)
, sRGB(isGammaCorrect() && !settings.linear)
, usingDefaultTexture(false) , usingDefaultTexture(false)
{ {
renderTarget = false;
sRGB = isGammaCorrect() && !settings.linear;
if (validatedata && data.validate() && data.getMipmapCount() > 1) if (validatedata && data.validate() && data.getMipmapCount() > 1)
mipmapsType = MIPMAPS_DATA; mipmapsType = MIPMAPS_DATA;
} }
@@ -72,13 +71,12 @@ Image::Image(const Slices &slices, const Settings &settings)
Image::~Image() Image::~Image()
{ {
--imageCount;
} }
void Image::init(PixelFormat fmt, int w, int h, const Settings &settings) void Image::init(PixelFormat fmt, int w, int h, const Settings &settings)
{ {
Graphics *gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS); Graphics *gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
if (gfx != nullptr && !gfx->isPixelFormatSupported(fmt, false, true, sRGB)) if (gfx != nullptr && !gfx->isPixelFormatSupported(fmt, renderTarget, readable, sRGB))
{ {
const char *str; const char *str;
if (love::getConstant(fmt, str)) if (love::getConstant(fmt, str))
@@ -104,8 +102,6 @@ void Image::init(PixelFormat fmt, int w, int h, const Settings &settings)
mipmapCount = mipmapsType == MIPMAPS_NONE ? 1 : getTotalMipmapCount(w, h, depth); mipmapCount = mipmapsType == MIPMAPS_NONE ? 1 : getTotalMipmapCount(w, h, depth);
initQuad(); initQuad();
++imageCount;
} }
void Image::uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y) void Image::uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y)
@@ -172,16 +168,6 @@ void Image::replacePixels(const void *data, size_t size, int slice, int mipmap,
generateMipmaps(); generateMipmaps();
} }
bool Image::isCompressed() const
{
return isPixelFormatCompressed(format);
}
bool Image::isFormatLinear() const
{
return isGammaCorrect() && !sRGB && format != PIXELFORMAT_sRGBA8_UNORM;
}
Image::MipmapsType Image::getMipmapsType() const Image::MipmapsType Image::getMipmapsType() const
{ {
return mipmapsType; return mipmapsType;
-6
View File
@@ -58,11 +58,8 @@ public:
void replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps); void replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps);
bool isFormatLinear() const; bool isFormatLinear() const;
bool isCompressed() const;
MipmapsType getMipmapsType() const; MipmapsType getMipmapsType() const;
static int imageCount;
static bool getConstant(const char *in, SettingType &out); static bool getConstant(const char *in, SettingType &out);
static bool getConstant(SettingType in, const char *&out); static bool getConstant(SettingType in, const char *&out);
static const char *getConstant(SettingType in); static const char *getConstant(SettingType in);
@@ -76,13 +73,10 @@ protected:
void uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y); void uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y);
virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) = 0; virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) = 0;
virtual void generateMipmaps() = 0;
// The settings used to initialize this Image. // The settings used to initialize this Image.
Settings settings; Settings settings;
MipmapsType mipmapsType; MipmapsType mipmapsType;
bool sRGB;
// True if the image wasn't able to be properly created and it had to fall // True if the image wasn't able to be properly created and it had to fall
// back to a default texture. // back to a default texture.
+26
View File
@@ -156,12 +156,15 @@ std::vector<std::string> SamplerState::getConstants(WrapMode)
} }
love::Type Texture::type("Texture", &Drawable::type); love::Type Texture::type("Texture", &Drawable::type);
int Texture::textureCount = 0;
int64 Texture::totalGraphicsMemory = 0; int64 Texture::totalGraphicsMemory = 0;
Texture::Texture(TextureType texType) Texture::Texture(TextureType texType)
: texType(texType) : texType(texType)
, format(PIXELFORMAT_UNKNOWN) , format(PIXELFORMAT_UNKNOWN)
, renderTarget(false)
, readable(true) , readable(true)
, sRGB(false)
, width(0) , width(0)
, height(0) , height(0)
, depth(1) , depth(1)
@@ -175,10 +178,12 @@ Texture::Texture(TextureType texType)
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS); auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
if (gfx != nullptr) if (gfx != nullptr)
samplerState = gfx->getDefaultSamplerState(); samplerState = gfx->getDefaultSamplerState();
++textureCount;
} }
Texture::~Texture() Texture::~Texture()
{ {
--textureCount;
setGraphicsMemorySize(0); setGraphicsMemorySize(0);
} }
@@ -207,11 +212,26 @@ PixelFormat Texture::getPixelFormat() const
return format; return format;
} }
bool Texture::isRenderTarget() const
{
return renderTarget;
}
bool Texture::isReadable() const bool Texture::isReadable() const
{ {
return readable; return readable;
} }
bool Texture::isCompressed() const
{
return isPixelFormatCompressed(format);
}
bool Texture::isFormatLinear() const
{
return isGammaCorrect() && !sRGB && format != PIXELFORMAT_sRGBA8_UNORM;
}
bool Texture::isValidSlice(int slice) const bool Texture::isValidSlice(int slice) const
{ {
if (slice < 0) if (slice < 0)
@@ -241,6 +261,9 @@ void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform)
if (!readable) if (!readable)
throw love::Exception("Textures with non-readable formats cannot be drawn."); throw love::Exception("Textures with non-readable formats cannot be drawn.");
if (renderTarget && gfx->isRenderTargetActive(this))
throw love::Exception("Cannot render a Texture to itself.");
if (texType == TEXTURE_2D_ARRAY) if (texType == TEXTURE_2D_ARRAY)
{ {
drawLayer(gfx, q->getLayer(), q, localTransform); drawLayer(gfx, q->getLayer(), q, localTransform);
@@ -291,6 +314,9 @@ void Texture::drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &m)
if (!readable) if (!readable)
throw love::Exception("Textures with non-readable formats cannot be drawn."); throw love::Exception("Textures with non-readable formats cannot be drawn.");
if (renderTarget && gfx->isRenderTargetActive(this, layer))
throw love::Exception("Cannot render a Texture to itself.");
if (texType != TEXTURE_2D_ARRAY) if (texType != TEXTURE_2D_ARRAY)
throw love::Exception("drawLayer can only be used with Array Textures!"); throw love::Exception("drawLayer can only be used with Array Textures!");
+12 -2
View File
@@ -126,6 +126,7 @@ class Texture : public Drawable, public Resource
public: public:
static love::Type type; static love::Type type;
static int textureCount;
enum MipmapsType enum MipmapsType
{ {
@@ -175,16 +176,20 @@ public:
/** /**
* Draws the texture using the specified transformation with a Quad applied. * Draws the texture using the specified transformation with a Quad applied.
**/ **/
virtual void draw(Graphics *gfx, Quad *quad, const Matrix4 &m); void draw(Graphics *gfx, Quad *quad, const Matrix4 &m);
void drawLayer(Graphics *gfx, int layer, const Matrix4 &m); void drawLayer(Graphics *gfx, int layer, const Matrix4 &m);
virtual void drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m); void drawLayer(Graphics *gfx, int layer, Quad *quad, const Matrix4 &m);
TextureType getTextureType() const; TextureType getTextureType() const;
PixelFormat getPixelFormat() const; PixelFormat getPixelFormat() const;
bool isRenderTarget() const;
bool isReadable() const; bool isReadable() const;
bool isCompressed() const;
bool isFormatLinear() const;
bool isValidSlice(int slice) const; bool isValidSlice(int slice) const;
int getWidth(int mip = 0) const; int getWidth(int mip = 0) const;
@@ -201,6 +206,8 @@ public:
virtual void setSamplerState(const SamplerState &s); virtual void setSamplerState(const SamplerState &s);
const SamplerState &getSamplerState() const; const SamplerState &getSamplerState() const;
virtual void generateMipmaps() = 0;
Quad *getQuad() const; Quad *getQuad() const;
static int getTotalMipmapCount(int w, int h); static int getTotalMipmapCount(int w, int h);
@@ -220,8 +227,11 @@ protected:
TextureType texType; TextureType texType;
PixelFormat format; PixelFormat format;
bool renderTarget;
bool readable; bool readable;
bool sRGB;
int width; int width;
int height; int height;
+29 -38
View File
@@ -31,7 +31,7 @@ namespace graphics
namespace opengl namespace opengl
{ {
static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat format, GLuint texture, int layers, int nb_mips) static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat format, GLuint texture, int layers)
{ {
// get currently bound fbo to reset to it later // get currently bound fbo to reset to it later
GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL); GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
@@ -60,42 +60,35 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo
// Make sure all faces and layers of the texture are initialized to // Make sure all faces and layers of the texture are initialized to
// transparent black. This is unfortunately probably pretty slow for // transparent black. This is unfortunately probably pretty slow for
// 2D-array and 3D textures with a lot of layers... // 2D-array and 3D textures with a lot of layers...
for (int mip = nb_mips - 1; mip >= 0; mip--) for (int layer = layers - 1; layer >= 0; layer--)
{ {
int nlayers = layers; for (int face = faces - 1; face >= 0; face--)
if (texType == TEXTURE_VOLUME)
nlayers = std::max(layers >> mip, 1);
for (int layer = nlayers - 1; layer >= 0; layer--)
{ {
for (int face = faces - 1; face >= 0; face--) for (GLenum attachment : fmt.framebufferAttachments)
{ {
for (GLenum attachment : fmt.framebufferAttachments) if (attachment == GL_NONE)
{ continue;
if (attachment == GL_NONE)
continue;
gl.framebufferTexture(attachment, texType, texture, mip, layer, face); gl.framebufferTexture(attachment, texType, texture, 0, layer, face);
} }
if (isPixelFormatDepthStencil(format)) if (isPixelFormatDepthStencil(format))
{ {
bool hadDepthWrites = gl.hasDepthWrites(); bool hadDepthWrites = gl.hasDepthWrites();
if (!hadDepthWrites) // glDepthMask also affects glClear. if (!hadDepthWrites) // glDepthMask also affects glClear.
gl.setDepthWrites(true); gl.setDepthWrites(true);
gl.clearDepth(1.0); gl.clearDepth(1.0);
glClearStencil(0); glClearStencil(0);
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
if (!hadDepthWrites) if (!hadDepthWrites)
gl.setDepthWrites(hadDepthWrites); gl.setDepthWrites(hadDepthWrites);
} }
else else
{ {
glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
}
} }
} }
} }
@@ -198,7 +191,7 @@ Canvas::Canvas(const Settings &settings)
{ {
auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS); auto gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
if (gfx != nullptr) if (gfx != nullptr)
format = gfx->getSizedFormat(format); format = gfx->getSizedFormat(format, renderTarget, readable, sRGB);
initQuad(); initQuad();
loadVolatile(); loadVolatile();
@@ -259,8 +252,8 @@ bool Canvas::loadVolatile()
return false; return false;
} }
// Create a canvas-local FBO used for glReadPixels as well as MSAA blitting. // Create a local FBO used for glReadPixels as well as MSAA blitting.
status = createFBO(fbo, texType, format, texture, texType == TEXTURE_VOLUME ? depth : layers, mipmapCount); status = createFBO(fbo, texType, format, texture, texType == TEXTURE_VOLUME ? depth : layers);
if (status != GL_FRAMEBUFFER_COMPLETE) if (status != GL_FRAMEBUFFER_COMPLETE)
{ {
@@ -287,6 +280,9 @@ bool Canvas::loadVolatile()
setGraphicsMemorySize(memsize); setGraphicsMemorySize(memsize);
if (getMipmapCount() > 1)
generateMipmaps();
return true; return true;
} }
@@ -390,11 +386,6 @@ void Canvas::generateMipmaps()
glGenerateMipmap(gltextype); glGenerateMipmap(gltextype);
} }
bool Canvas::isMultiFormatMultiCanvasSupported()
{
return gl.getMaxRenderTargets() > 1 && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object);
}
} // opengl } // opengl
} // graphics } // graphics
} // love } // love
-2
View File
@@ -68,8 +68,6 @@ public:
return fbo; return fbo;
} }
static bool isMultiFormatMultiCanvasSupported();
private: private:
GLuint fbo; GLuint fbo;
+5 -5
View File
@@ -1362,7 +1362,7 @@ void Graphics::getAPIStats(int &shaderswitches) const
void Graphics::initCapabilities() void Graphics::initCapabilities()
{ {
capabilities.features[FEATURE_MULTI_CANVAS_FORMATS] = Canvas::isMultiFormatMultiCanvasSupported(); capabilities.features[FEATURE_MULTI_CANVAS_FORMATS] = gl.isMultiFormatMRTSupported();
capabilities.features[FEATURE_CLAMP_ZERO] = gl.isClampZeroOneTextureWrapSupported(); capabilities.features[FEATURE_CLAMP_ZERO] = gl.isClampZeroOneTextureWrapSupported();
capabilities.features[FEATURE_BLENDMINMAX] = GLAD_VERSION_1_4 || GLAD_ES_VERSION_3_0 || GLAD_EXT_blend_minmax; capabilities.features[FEATURE_BLENDMINMAX] = GLAD_VERSION_1_4 || GLAD_ES_VERSION_3_0 || GLAD_EXT_blend_minmax;
capabilities.features[FEATURE_LIGHTEN] = capabilities.features[FEATURE_BLENDMINMAX]; capabilities.features[FEATURE_LIGHTEN] = capabilities.features[FEATURE_BLENDMINMAX];
@@ -1388,14 +1388,14 @@ void Graphics::initCapabilities()
capabilities.textureTypes[i] = gl.isTextureTypeSupported((TextureType) i); capabilities.textureTypes[i] = gl.isTextureTypeSupported((TextureType) i);
} }
PixelFormat Graphics::getSizedFormat(PixelFormat format) const PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable, bool sRGB) const
{ {
switch (format) switch (format)
{ {
case PIXELFORMAT_NORMAL: case PIXELFORMAT_NORMAL:
if (isGammaCorrect()) if (isGammaCorrect())
return PIXELFORMAT_sRGBA8_UNORM; return PIXELFORMAT_sRGBA8_UNORM;
else if (!OpenGL::isPixelFormatSupported(PIXELFORMAT_RGBA8_UNORM, true, true, false)) else if (!OpenGL::isPixelFormatSupported(PIXELFORMAT_RGBA8_UNORM, rendertarget, readable, sRGB))
// 32-bit render targets don't have guaranteed support on GLES2. // 32-bit render targets don't have guaranteed support on GLES2.
return PIXELFORMAT_RGBA4_UNORM; return PIXELFORMAT_RGBA4_UNORM;
else else
@@ -1409,14 +1409,14 @@ PixelFormat Graphics::getSizedFormat(PixelFormat format) const
bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB) bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB)
{ {
format = getSizedFormat(format);
if (sRGB && format == PIXELFORMAT_RGBA8_UNORM) if (sRGB && format == PIXELFORMAT_RGBA8_UNORM)
{ {
format = PIXELFORMAT_sRGBA8_UNORM; format = PIXELFORMAT_sRGBA8_UNORM;
sRGB = false; sRGB = false;
} }
format = getSizedFormat(format, rendertarget, readable, sRGB);
OptionalBool &supported = supportedFormats[format][rendertarget ? 1 : 0][readable ? 1 : 0][sRGB ? 1 : 0]; OptionalBool &supported = supportedFormats[format][rendertarget ? 1 : 0][readable ? 1 : 0][sRGB ? 1 : 0];
if (supported.hasValue) if (supported.hasValue)
+1 -1
View File
@@ -104,7 +104,7 @@ public:
void setWireframe(bool enable) override; void setWireframe(bool enable) override;
PixelFormat getSizedFormat(PixelFormat format) const override; PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable, bool sRGB) const override;
bool isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB = false) override; bool isPixelFormatSupported(PixelFormat format, bool rendertarget, bool readable, bool sRGB = false) override;
Renderer getRenderer() const override; Renderer getRenderer() const override;
RendererInfo getRendererInfo() const override; RendererInfo getRendererInfo() const override;
+10 -7
View File
@@ -105,9 +105,6 @@ void Image::loadData()
if (!isCompressed()) if (!isCompressed())
gl.rawTexStorage(texType, mipcount, format, sRGB, pixelWidth, pixelHeight, texType == TEXTURE_VOLUME ? depth : layers); gl.rawTexStorage(texType, mipcount, format, sRGB, pixelWidth, pixelHeight, texType == TEXTURE_VOLUME ? depth : layers);
if (mipmapsType == MIPMAPS_GENERATED)
mipcount = 1;
int w = pixelWidth; int w = pixelWidth;
int h = pixelHeight; int h = pixelHeight;
int d = depth; int d = depth;
@@ -123,17 +120,23 @@ void Image::loadData()
if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME) if (texType == TEXTURE_2D_ARRAY || texType == TEXTURE_VOLUME)
{ {
for (int slice = 0; slice < slices.getSliceCount(mip); slice++) for (int slice = 0; slice < slices.getSliceCount(mip); slice++)
mipsize += slices.get(slice, mip)->getSize(); {
auto id = slices.get(slice, mip);
if (id != nullptr)
mipsize += id->getSize();
}
} }
GLenum gltarget = OpenGL::getGLTextureType(texType); if (mipsize > 0)
glCompressedTexImage3D(gltarget, mip, fmt.internalformat, w, h, d, 0, mipsize, nullptr); {
GLenum gltarget = OpenGL::getGLTextureType(texType);
glCompressedTexImage3D(gltarget, mip, fmt.internalformat, w, h, d, 0, mipsize, nullptr);
}
} }
for (int slice = 0; slice < slicecount; slice++) for (int slice = 0; slice < slicecount; slice++)
{ {
love::image::ImageDataBase *id = slices.get(slice, mip); love::image::ImageDataBase *id = slices.get(slice, mip);
if (id != nullptr) if (id != nullptr)
uploadImageData(id, mip, slice, 0, 0); uploadImageData(id, mip, slice, 0, 0);
} }
+1 -1
View File
@@ -50,11 +50,11 @@ public:
ptrdiff_t getHandle() const override; ptrdiff_t getHandle() const override;
void setSamplerState(const SamplerState &s) override; void setSamplerState(const SamplerState &s) override;
void generateMipmaps() override;
private: private:
void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override; void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r, love::image::ImageDataBase *imgd = nullptr) override;
void generateMipmaps() override;
void loadDefaultTexture(); void loadDefaultTexture();
void loadData(); void loadData();
+5
View File
@@ -1328,6 +1328,11 @@ bool OpenGL::isBaseVertexSupported() const
return baseVertexSupported; return baseVertexSupported;
} }
bool OpenGL::isMultiFormatMRTSupported() const
{
return getMaxRenderTargets() > 1 && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object);
}
int OpenGL::getMax2DTextureSize() const int OpenGL::getMax2DTextureSize() const
{ {
return std::max(max2DTextureSize, 1); return std::max(max2DTextureSize, 1);
+1
View File
@@ -347,6 +347,7 @@ public:
bool isDepthCompareSampleSupported() const; bool isDepthCompareSampleSupported() const;
bool isSamplerLODBiasSupported() const; bool isSamplerLODBiasSupported() const;
bool isBaseVertexSupported() const; bool isBaseVertexSupported() const;
bool isMultiFormatMRTSupported() const;
/** /**
* Returns the maximum supported width or height of a texture. * Returns the maximum supported width or height of a texture.
+2 -5
View File
@@ -2394,11 +2394,8 @@ int w_getStats(lua_State *L)
lua_pushinteger(L, stats.shaderSwitches); lua_pushinteger(L, stats.shaderSwitches);
lua_setfield(L, -2, "shaderswitches"); lua_setfield(L, -2, "shaderswitches");
lua_pushinteger(L, stats.canvases); lua_pushinteger(L, stats.textures);
lua_setfield(L, -2, "canvases"); lua_setfield(L, -2, "textures");
lua_pushinteger(L, stats.images);
lua_setfield(L, -2, "images");
lua_pushinteger(L, stats.fonts); lua_pushinteger(L, stats.fonts);
lua_setfield(L, -2, "fonts"); lua_setfield(L, -2, "fonts");