mirror of
https://github.com/love2d/love.git
synced 2026-08-20 04:30:09 +02:00
Move some Canvas code to Texture, devirtualize Texture::draw.
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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!");
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -68,8 +68,6 @@ public:
|
|||||||
return fbo;
|
return fbo;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isMultiFormatMultiCanvasSupported();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
GLuint fbo;
|
GLuint fbo;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
Reference in New Issue
Block a user