Begin unification of Canvases and Images.

This commit is contained in:
Alex Szpakowski
2020-02-03 23:05:46 -04:00
parent fc0d60a96d
commit 63c5df6aa7
16 changed files with 211 additions and 225 deletions
+1 -25
View File
@@ -102,7 +102,7 @@ Canvas::~Canvas()
{
}
Canvas::MipmapMode Canvas::getMipmapMode() const
Texture::MipmapsMode Canvas::getMipmapsMode() const
{
return settings.mipmaps;
}
@@ -141,21 +141,6 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *module, int sli
return module->newImageData(r.w, r.h, dataformat);
}
bool Canvas::getConstant(const char *in, MipmapMode &out)
{
return mipmapModes.find(in, out);
}
bool Canvas::getConstant(MipmapMode in, const char *&out)
{
return mipmapModes.find(in, out);
}
std::vector<std::string> Canvas::getConstants(MipmapMode)
{
return mipmapModes.getNames();
}
bool Canvas::getConstant(const char *in, SettingType &out)
{
return settingTypes.find(in, out);
@@ -178,15 +163,6 @@ std::vector<std::string> Canvas::getConstants(SettingType)
return settingTypes.getNames();
}
StringMap<Canvas::MipmapMode, Canvas::MIPMAPS_MAX_ENUM>::Entry Canvas::mipmapEntries[] =
{
{ "none", MIPMAPS_NONE },
{ "manual", MIPMAPS_MANUAL },
{ "auto", MIPMAPS_AUTO },
};
StringMap<Canvas::MipmapMode, Canvas::MIPMAPS_MAX_ENUM> Canvas::mipmapModes(Canvas::mipmapEntries, sizeof(Canvas::mipmapEntries));
StringMap<Canvas::SettingType, Canvas::SETTING_MAX_ENUM>::Entry Canvas::settingTypeEntries[] =
{
// Width / height / layers are currently omittted because they're separate
+4 -16
View File
@@ -39,14 +39,6 @@ public:
static love::Type type;
enum MipmapMode
{
MIPMAPS_NONE,
MIPMAPS_MANUAL,
MIPMAPS_AUTO,
MIPMAPS_MAX_ENUM
};
enum SettingType
{
SETTING_WIDTH,
@@ -66,7 +58,7 @@ public:
int width = 1;
int height = 1;
int layers = 1; // depth for 3D textures
MipmapMode mipmaps = MIPMAPS_NONE;
MipmapsMode mipmaps = MIPMAPS_NONE;
PixelFormat format = PIXELFORMAT_NORMAL;
TextureType type = TEXTURE_2D;
float dpiScale = 1.0f;
@@ -77,14 +69,10 @@ public:
Canvas(const Settings &settings);
virtual ~Canvas();
MipmapMode getMipmapMode() const;
MipmapsMode getMipmapsMode() const;
virtual love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect);
static bool getConstant(const char *in, MipmapMode &out);
static bool getConstant(MipmapMode in, const char *&out);
static std::vector<std::string> getConstants(MipmapMode);
static bool getConstant(const char *in, SettingType &out);
static bool getConstant(SettingType in, const char *&out);
static const char *getConstant(SettingType in);
@@ -96,8 +84,8 @@ protected:
private:
static StringMap<MipmapMode, MIPMAPS_MAX_ENUM>::Entry mipmapEntries[];
static StringMap<MipmapMode, MIPMAPS_MAX_ENUM> mipmapModes;
static StringMap<MipmapsMode, MIPMAPS_MAX_ENUM>::Entry mipmapEntries[];
static StringMap<MipmapsMode, MIPMAPS_MAX_ENUM> mipmapModes;
static StringMap<SettingType, SETTING_MAX_ENUM>::Entry settingTypeEntries[];
static StringMap<SettingType, SETTING_MAX_ENUM> settingTypes;
+56 -47
View File
@@ -116,7 +116,7 @@ Graphics::Graphics()
, writingToStencil(false)
, streamBufferState()
, projectionMatrix()
, canvasSwitchCount(0)
, renderTargetSwitchCount(0)
, drawCalls(0)
, drawCallsBatched(0)
, quadIndexBuffer(nullptr)
@@ -335,8 +335,8 @@ int Graphics::getPixelHeight() const
double Graphics::getCurrentDPIScale() const
{
const auto &rt = states.back().renderTargets.getFirstTarget();
if (rt.canvas.get())
return rt.canvas->getDPIScale();
if (rt.texture.get())
return rt.texture->getDPIScale();
return getScreenDPIScale();
}
@@ -545,7 +545,7 @@ love::graphics::Shader *Graphics::getShader() const
void Graphics::setCanvas(RenderTarget rt, uint32 temporaryRTFlags)
{
if (rt.canvas == nullptr)
if (rt.texture == nullptr)
return setCanvas();
RenderTargets rts;
@@ -561,9 +561,9 @@ void Graphics::setCanvas(const RenderTargetsStrongRef &rts)
targets.colors.reserve(rts.colors.size());
for (const auto &rt : rts.colors)
targets.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap);
targets.colors.emplace_back(rt.texture.get(), rt.slice, rt.mipmap);
targets.depthStencil = RenderTarget(rts.depthStencil.canvas, rts.depthStencil.slice, rts.depthStencil.mipmap);
targets.depthStencil = RenderTarget(rts.depthStencil.texture, rts.depthStencil.slice, rts.depthStencil.mipmap);
targets.temporaryRTFlags = rts.temporaryRTFlags;
return setCanvas(targets);
@@ -575,9 +575,9 @@ void Graphics::setCanvas(const RenderTargets &rts)
int ncanvases = (int) rts.colors.size();
RenderTarget firsttarget = rts.getFirstTarget();
love::graphics::Canvas *firstcanvas = firsttarget.canvas;
Texture *firsttex = firsttarget.texture;
if (firstcanvas == nullptr)
if (firsttex == nullptr)
return setCanvas();
const auto &prevRTs = state.renderTargets;
@@ -612,29 +612,35 @@ void Graphics::setCanvas(const RenderTargets &rts)
PixelFormat firstcolorformat = PIXELFORMAT_UNKNOWN;
if (!rts.colors.empty())
firstcolorformat = rts.colors[0].canvas->getPixelFormat();
firstcolorformat = rts.colors[0].texture->getPixelFormat();
if (!firsttex->isRenderTarget())
throw love::Exception("Texture must be created as a render target to be used in setCanvas.");
if (isPixelFormatDepthStencil(firstcolorformat))
throw love::Exception("Depth/stencil format Canvases must be used with the 'depthstencil' field of the table passed into setCanvas.");
if (firsttarget.mipmap < 0 || firsttarget.mipmap >= firstcanvas->getMipmapCount())
if (firsttarget.mipmap < 0 || firsttarget.mipmap >= firsttex->getMipmapCount())
throw love::Exception("Invalid mipmap level %d.", firsttarget.mipmap + 1);
if (!firstcanvas->isValidSlice(firsttarget.slice))
if (!firsttex->isValidSlice(firsttarget.slice))
throw love::Exception("Invalid slice index: %d.", firsttarget.slice + 1);
bool hasSRGBcanvas = firstcolorformat == PIXELFORMAT_sRGBA8_UNORM;
int pixelw = firstcanvas->getPixelWidth(firsttarget.mipmap);
int pixelh = firstcanvas->getPixelHeight(firsttarget.mipmap);
int reqmsaa = firstcanvas->getRequestedMSAA();
int pixelw = firsttex->getPixelWidth(firsttarget.mipmap);
int pixelh = firsttex->getPixelHeight(firsttarget.mipmap);
int reqmsaa = firsttex->getRequestedMSAA();
for (int i = 1; i < ncanvases; i++)
{
love::graphics::Canvas *c = rts.colors[i].canvas;
Texture *c = rts.colors[i].texture;
PixelFormat format = c->getPixelFormat();
int mip = rts.colors[i].mipmap;
int slice = rts.colors[i].slice;
if (!c->isRenderTarget())
throw love::Exception("Texture must be created as a render target to be used in setCanvas.");
if (mip < 0 || mip >= c->getMipmapCount())
throw love::Exception("Invalid mipmap level %d.", mip + 1);
@@ -657,20 +663,23 @@ void Graphics::setCanvas(const RenderTargets &rts)
hasSRGBcanvas = true;
}
if (rts.depthStencil.canvas != nullptr)
if (rts.depthStencil.texture != nullptr)
{
love::graphics::Canvas *c = rts.depthStencil.canvas;
Texture *c = rts.depthStencil.texture;
int mip = rts.depthStencil.mipmap;
int slice = rts.depthStencil.slice;
if (!c->isRenderTarget())
throw love::Exception("Texture must be created as a render target to be used in setCanvas.");
if (!isPixelFormatDepthStencil(c->getPixelFormat()))
throw love::Exception("Only depth/stencil format Canvases can be used with the 'depthstencil' field of the table passed into setCanvas.");
throw love::Exception("Only depth/stencil format Texture can be used with the 'depthstencil' field of the table passed into setCanvas.");
if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh)
throw love::Exception("All canvases must have the same pixel dimensions.");
throw love::Exception("All Textures must have the same pixel dimensions.");
if (c->getRequestedMSAA() != firstcanvas->getRequestedMSAA())
throw love::Exception("All Canvases must have the same MSAA value.");
if (c->getRequestedMSAA() != firsttex->getRequestedMSAA())
throw love::Exception("All Textures must have the same MSAA value.");
if (mip < 0 || mip >= c->getMipmapCount())
throw love::Exception("Invalid mipmap level %d.", mip + 1);
@@ -679,12 +688,12 @@ void Graphics::setCanvas(const RenderTargets &rts)
throw love::Exception("Invalid slice index: %d.", slice + 1);
}
int w = firstcanvas->getWidth(firsttarget.mipmap);
int h = firstcanvas->getHeight(firsttarget.mipmap);
int w = firsttex->getWidth(firsttarget.mipmap);
int h = firsttex->getHeight(firsttarget.mipmap);
flushStreamDraws();
if (rts.depthStencil.canvas == nullptr && rts.temporaryRTFlags != 0)
if (rts.depthStencil.texture == nullptr && rts.temporaryRTFlags != 0)
{
bool wantsdepth = (rts.temporaryRTFlags & TEMPORARY_RT_DEPTH) != 0;
bool wantsstencil = (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) != 0;
@@ -703,7 +712,7 @@ void Graphics::setCanvas(const RenderTargets &rts)
// we don't want to directly store it in the main graphics state.
RenderTargets realRTs = rts;
realRTs.depthStencil.canvas = getTemporaryCanvas(dsformat, pixelw, pixelh, reqmsaa);
realRTs.depthStencil.texture = getTemporaryTexture(dsformat, pixelw, pixelh, reqmsaa);
realRTs.depthStencil.slice = 0;
setCanvasInternal(realRTs, w, h, pixelw, pixelh, hasSRGBcanvas);
@@ -715,28 +724,28 @@ void Graphics::setCanvas(const RenderTargets &rts)
refs.colors.reserve(rts.colors.size());
for (auto c : rts.colors)
refs.colors.emplace_back(c.canvas, c.slice, c.mipmap);
refs.colors.emplace_back(c.texture, c.slice, c.mipmap);
refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.canvas, rts.depthStencil.slice);
refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.texture, rts.depthStencil.slice);
refs.temporaryRTFlags = rts.temporaryRTFlags;
std::swap(state.renderTargets, refs);
canvasSwitchCount++;
renderTargetSwitchCount++;
}
void Graphics::setCanvas()
{
DisplayState &state = states.back();
if (state.renderTargets.colors.empty() && state.renderTargets.depthStencil.canvas == nullptr)
if (state.renderTargets.colors.empty() && state.renderTargets.depthStencil.texture == nullptr)
return;
flushStreamDraws();
setCanvasInternal(RenderTargets(), width, height, pixelWidth, pixelHeight, isGammaCorrect());
state.renderTargets = RenderTargetsStrongRef();
canvasSwitchCount++;
renderTargetSwitchCount++;
}
Graphics::RenderTargets Graphics::getCanvas() const
@@ -747,9 +756,9 @@ Graphics::RenderTargets Graphics::getCanvas() const
rts.colors.reserve(curRTs.colors.size());
for (const auto &rt : curRTs.colors)
rts.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap);
rts.colors.emplace_back(rt.texture.get(), rt.slice, rt.mipmap);
rts.depthStencil = RenderTarget(curRTs.depthStencil.canvas, curRTs.depthStencil.slice, curRTs.depthStencil.mipmap);
rts.depthStencil = RenderTarget(curRTs.depthStencil.texture, curRTs.depthStencil.slice, curRTs.depthStencil.mipmap);
rts.temporaryRTFlags = curRTs.temporaryRTFlags;
return rts;
@@ -758,7 +767,7 @@ Graphics::RenderTargets Graphics::getCanvas() const
bool Graphics::isCanvasActive() const
{
const auto &rts = states.back().renderTargets;
return !rts.colors.empty() || rts.depthStencil.canvas != nullptr;
return !rts.colors.empty() || rts.depthStencil.texture != nullptr;
}
bool Graphics::isRenderTargetActive(Texture *texture) const
@@ -767,11 +776,11 @@ bool Graphics::isRenderTargetActive(Texture *texture) const
for (const auto &rt : rts.colors)
{
if (rt.canvas.get() == texture)
if (rt.texture.get() == texture)
return true;
}
if (rts.depthStencil.canvas.get() == texture)
if (rts.depthStencil.texture.get() == texture)
return true;
return false;
@@ -783,33 +792,33 @@ bool Graphics::isRenderTargetActive(Texture *texture, int slice) const
for (const auto &rt : rts.colors)
{
if (rt.canvas.get() == texture && rt.slice == slice)
if (rt.texture.get() == texture && rt.slice == slice)
return true;
}
if (rts.depthStencil.canvas.get() == texture && rts.depthStencil.slice == slice)
if (rts.depthStencil.texture.get() == texture && rts.depthStencil.slice == slice)
return true;
return false;
}
Canvas *Graphics::getTemporaryCanvas(PixelFormat format, int w, int h, int samples)
Texture *Graphics::getTemporaryTexture(PixelFormat format, int w, int h, int samples)
{
love::graphics::Canvas *canvas = nullptr;
Texture *texture = nullptr;
for (TemporaryCanvas &temp : temporaryCanvases)
for (TemporaryTexture &temp : temporaryTextures)
{
Canvas *c = temp.canvas;
Texture *c = temp.texture;
if (c->getPixelFormat() == format && c->getPixelWidth() == w
&& c->getPixelHeight() == h && c->getRequestedMSAA() == samples)
{
canvas = c;
texture = c;
temp.framesSinceUse = 0;
break;
}
}
if (canvas == nullptr)
if (texture == nullptr)
{
Canvas::Settings settings;
settings.format = format;
@@ -817,12 +826,12 @@ Canvas *Graphics::getTemporaryCanvas(PixelFormat format, int w, int h, int sampl
settings.height = h;
settings.msaa = samples;
canvas = newCanvas(settings);
texture = newCanvas(settings);
temporaryCanvases.emplace_back(canvas);
temporaryTextures.emplace_back(texture);
}
return canvas;
return texture;
}
void Graphics::intersectScissor(const Rect &rect)
@@ -1591,7 +1600,7 @@ Graphics::Stats Graphics::getStats() const
if (streamBufferState.vertexCount > 0)
stats.drawCalls++;
stats.canvasSwitches = canvasSwitchCount;
stats.renderTargetSwitches = renderTargetSwitchCount;
stats.drawCallsBatched = drawCallsBatched;
stats.textures = Texture::textureCount;
stats.fonts = Font::fontCount;
+22 -22
View File
@@ -200,7 +200,7 @@ public:
{
int drawCalls;
int drawCallsBatched;
int canvasSwitches;
int renderTargetSwitches;
int shaderSwitches;
int textures;
int fonts;
@@ -315,53 +315,53 @@ public:
struct RenderTarget
{
Canvas *canvas;
Texture *texture;
int slice;
int mipmap;
RenderTarget(Canvas *canvas, int slice = 0, int mipmap = 0)
: canvas(canvas)
RenderTarget(Texture *texture, int slice = 0, int mipmap = 0)
: texture(texture)
, slice(slice)
, mipmap(mipmap)
{}
RenderTarget()
: canvas(nullptr)
: texture(nullptr)
, slice(0)
, mipmap(0)
{}
bool operator != (const RenderTarget &other) const
{
return canvas != other.canvas || slice != other.slice || mipmap != other.mipmap;
return texture != other.texture || slice != other.slice || mipmap != other.mipmap;
}
bool operator != (const RenderTargetStrongRef &other) const
{
return canvas != other.canvas.get() || slice != other.slice || mipmap != other.mipmap;
return texture != other.texture.get() || slice != other.slice || mipmap != other.mipmap;
}
};
struct RenderTargetStrongRef
{
StrongRef<Canvas> canvas;
StrongRef<Texture> texture;
int slice = 0;
int mipmap = 0;
RenderTargetStrongRef(Canvas *canvas, int slice = 0, int mipmap = 0)
: canvas(canvas)
RenderTargetStrongRef(Texture *texture, int slice = 0, int mipmap = 0)
: texture(texture)
, slice(slice)
, mipmap(mipmap)
{}
bool operator != (const RenderTargetStrongRef &other) const
{
return canvas.get() != other.canvas.get() || slice != other.slice || mipmap != other.mipmap;
return texture.get() != other.texture.get() || slice != other.slice || mipmap != other.mipmap;
}
bool operator != (const RenderTarget &other) const
{
return canvas.get() != other.canvas || slice != other.slice || mipmap != other.mipmap;
return texture.get() != other.texture || slice != other.slice || mipmap != other.mipmap;
}
};
@@ -619,12 +619,12 @@ public:
const BlendState &getBlendState() const;
/**
* Sets the default sampler state for images, canvases, and fonts.
* Sets the default sampler state for textures, videos, and fonts.
**/
void setDefaultSamplerState(const SamplerState &s);
/**
* Gets the default sampler state for images, canvases, and fonts.
* Gets the default sampler state for textures, videos, and fonts.
**/
const SamplerState &getDefaultSamplerState() const;
@@ -939,13 +939,13 @@ protected:
}
};
struct TemporaryCanvas
struct TemporaryTexture
{
Canvas *canvas;
Texture *texture;
int framesSinceUse;
TemporaryCanvas(Canvas *c)
: canvas(c)
TemporaryTexture(Texture *tex)
: texture(tex)
, framesSinceUse(0)
{}
};
@@ -961,7 +961,7 @@ protected:
void createQuadIndexBuffer();
Canvas *getTemporaryCanvas(PixelFormat format, int w, int h, int samples);
Texture *getTemporaryTexture(PixelFormat format, int w, int h, int samples);
void restoreState(const DisplayState &s);
void restoreStateChecked(const DisplayState &s);
@@ -994,9 +994,9 @@ protected:
std::vector<DisplayState> states;
std::vector<StackType> stackTypeStack;
std::vector<TemporaryCanvas> temporaryCanvases;
std::vector<TemporaryTexture> temporaryTextures;
int canvasSwitchCount;
int renderTargetSwitchCount;
int drawCalls;
int drawCallsBatched;
@@ -1007,7 +1007,7 @@ protected:
Deprecations deprecations;
static const size_t MAX_USER_STACK_DEPTH = 128;
static const int MAX_TEMPORARY_CANVAS_UNUSED_FRAMES = 16;
static const int MAX_TEMPORARY_TEXTURE_UNUSED_FRAMES = 16;
private:
+16 -20
View File
@@ -31,20 +31,17 @@ namespace graphics
love::Type Image::type("Image", &Texture::type);
Image::Image(const Slices &data, const Settings &settings, bool validatedata)
: Texture(data.getTextureType())
Image::Image(TextureType textype, const Settings &settings)
: Texture(textype)
, settings(settings)
, mipmapsType(settings.mipmaps ? MIPMAPS_GENERATED : MIPMAPS_NONE)
, usingDefaultTexture(false)
{
renderTarget = false;
sRGB = isGammaCorrect() && !settings.linear;
if (validatedata && data.validate() && data.getMipmapCount() > 1)
mipmapsType = MIPMAPS_DATA;
}
Image::Image(TextureType textype, PixelFormat format, int width, int height, int slices, const Settings &settings)
: Image(Slices(textype), settings, false)
: Image(textype, settings)
{
if (isPixelFormatCompressed(format))
throw love::Exception("This constructor is only supported for non-compressed pixel formats.");
@@ -54,26 +51,30 @@ Image::Image(TextureType textype, PixelFormat format, int width, int height, int
else if (textype == TEXTURE_VOLUME)
depth = slices;
init(format, width, height, settings);
init(format, width, height, 1, settings);
}
Image::Image(const Slices &slices, const Settings &settings)
: Image(slices, settings, true)
: Image(slices.getTextureType(), settings)
{
int dataMipmaps = 1;
if (slices.validate() && slices.getMipmapCount() > 1)
dataMipmaps = slices.getMipmapCount();
if (texType == TEXTURE_2D_ARRAY)
this->layers = slices.getSliceCount();
else if (texType == TEXTURE_VOLUME)
this->depth = slices.getSliceCount();
love::image::ImageDataBase *slice = slices.get(0, 0);
init(slice->getFormat(), slice->getWidth(), slice->getHeight(), settings);
init(slice->getFormat(), slice->getWidth(), slice->getHeight(), dataMipmaps, settings);
}
Image::~Image()
{
}
void Image::init(PixelFormat fmt, int w, int h, const Settings &settings)
void Image::init(PixelFormat fmt, int w, int h, int dataMipmaps, const Settings &settings)
{
Graphics *gfx = Module::getInstance<Graphics>(Module::M_GRAPHICS);
if (gfx != nullptr && !gfx->isPixelFormatSupported(fmt, renderTarget, readable, sRGB))
@@ -96,10 +97,10 @@ void Image::init(PixelFormat fmt, int w, int h, const Settings &settings)
format = fmt;
if (isCompressed() && mipmapsType == MIPMAPS_GENERATED)
mipmapsType = MIPMAPS_NONE;
mipmapCount = mipmapsType == MIPMAPS_NONE ? 1 : getTotalMipmapCount(w, h, depth);
if (!settings.mipmaps || (isCompressed() && dataMipmaps <= 1))
mipmapCount = 1;
else
mipmapCount = getTotalMipmapCount(w, h, depth);
initQuad();
}
@@ -125,7 +126,7 @@ void Image::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap,
if (d->getFormat() != getPixelFormat())
throw love::Exception("Pixel formats must match.");
if (mipmap < 0 || (mipmapsType != MIPMAPS_DATA && mipmap > 0) || mipmap >= getMipmapCount())
if (mipmap < 0 || mipmap >= getMipmapCount())
throw love::Exception("Invalid image mipmap index %d.", mipmap + 1);
if (slice < 0 || (texType == TEXTURE_CUBE && slice >= 6)
@@ -168,11 +169,6 @@ void Image::replacePixels(const void *data, size_t size, int slice, int mipmap,
generateMipmaps();
}
Image::MipmapsType Image::getMipmapsType() const
{
return mipmapsType;
}
bool Image::getConstant(const char *in, SettingType &out)
{
return settingTypes.find(in, out);
+2 -6
View File
@@ -57,8 +57,6 @@ public:
void replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps);
void replacePixels(const void *data, size_t size, int slice, int mipmap, const Rect &rect, bool reloadmipmaps);
MipmapsType getMipmapsType() const;
static bool getConstant(const char *in, SettingType &out);
static bool getConstant(SettingType in, const char *&out);
static const char *getConstant(SettingType in);
@@ -75,17 +73,15 @@ protected:
// The settings used to initialize this Image.
Settings settings;
MipmapsType mipmapsType;
// True if the image wasn't able to be properly created and it had to fall
// back to a default texture.
bool usingDefaultTexture;
private:
Image(const Slices &data, const Settings &settings, bool validatedata);
Image(TextureType textype, const Settings &settings);
void init(PixelFormat fmt, int w, int h, const Settings &settings);
void init(PixelFormat fmt, int w, int h, int dataMipmaps, const Settings &settings);
static StringMap<SettingType, SETTING_MAX_ENUM>::Entry settingTypeEntries[];
static StringMap<SettingType, SETTING_MAX_ENUM> settingTypes;
+24
View File
@@ -680,5 +680,29 @@ StringMap<TextureType, TEXTURE_MAX_ENUM>::Entry Texture::texTypeEntries[] =
StringMap<TextureType, TEXTURE_MAX_ENUM> Texture::texTypes(Texture::texTypeEntries, sizeof(Texture::texTypeEntries));
static StringMap<Texture::MipmapsMode, Texture::MIPMAPS_MAX_ENUM>::Entry mipmapEntries[] =
{
{ "none", Texture::MIPMAPS_NONE },
{ "manual", Texture::MIPMAPS_MANUAL },
{ "auto", Texture::MIPMAPS_AUTO },
};
static StringMap<Texture::MipmapsMode, Texture::MIPMAPS_MAX_ENUM> mipmapModes(mipmapEntries, sizeof(mipmapEntries));
bool Texture::getConstant(const char *in, MipmapsMode &out)
{
return mipmapModes.find(in, out);
}
bool Texture::getConstant(MipmapsMode in, const char *&out)
{
return mipmapModes.find(in, out);
}
std::vector<std::string> Texture::getConstants(MipmapsMode)
{
return mipmapModes.getNames();
}
} // graphics
} // love
+8 -3
View File
@@ -128,11 +128,12 @@ public:
static love::Type type;
static int textureCount;
enum MipmapsType
enum MipmapsMode
{
MIPMAPS_NONE,
MIPMAPS_DATA,
MIPMAPS_GENERATED,
MIPMAPS_MANUAL,
MIPMAPS_AUTO,
MIPMAPS_MAX_ENUM
};
struct Slices
@@ -222,6 +223,10 @@ public:
static bool getConstant(TextureType in, const char *&out);
static std::vector<std::string> getConstants(TextureType);
static bool getConstant(const char *in, MipmapsMode &out);
static bool getConstant(MipmapsMode in, const char *&out);
static std::vector<std::string> getConstants(MipmapsMode);
protected:
void initQuad();
+5 -2
View File
@@ -373,8 +373,11 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *module, int sli
void Canvas::generateMipmaps()
{
if (getMipmapCount() == 1 || getMipmapMode() == MIPMAPS_NONE)
throw love::Exception("generateMipmaps can only be called on a Canvas which was created with mipmaps enabled.");
if (getMipmapCount() == 1 || getMipmapsMode() == MIPMAPS_NONE)
throw love::Exception("generateMipmaps can only be called on a Texture which was created with mipmaps enabled.");
if (isPixelFormatCompressed(format))
throw love::Exception("generateMipmaps cannot be called on a compressed Texture.");
gl.bindTextureToUnit(this, 0, false);
+42 -37
View File
@@ -234,7 +234,7 @@ bool Graphics::setMode(int width, int height, int pixelwidth, int pixelheight, b
// Set whether drawing converts input from linear -> sRGB colorspace.
if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB
|| GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB)
|| GLAD_ES_VERSION_3_0)
{
if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, isGammaCorrect());
@@ -312,11 +312,11 @@ void Graphics::unSetMode()
for (const auto &pair : framebufferObjects)
gl.deleteFramebuffer(pair.second);
for (auto temp : temporaryCanvases)
temp.canvas->release();
for (auto temp : temporaryTextures)
temp.texture->release();
framebufferObjects.clear();
temporaryCanvases.clear();
temporaryTextures.clear();
if (mainVAO != 0)
{
@@ -518,7 +518,7 @@ void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pix
flushStreamDraws();
endPass();
bool iswindow = rts.getFirstTarget().canvas == nullptr;
bool iswindow = rts.getFirstTarget().texture == nullptr;
vertex::Winding vertexwinding = state.winding;
if (iswindow)
@@ -560,7 +560,7 @@ void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pix
void Graphics::endPass()
{
auto &rts = states.back().renderTargets;
love::graphics::Canvas *depthstencil = rts.depthStencil.canvas.get();
love::graphics::Texture *depthstencil = rts.depthStencil.texture.get();
// Discard the depth/stencil buffer if we're using an internal cached one.
if (depthstencil == nullptr && (rts.temporaryRTFlags & (TEMPORARY_RT_DEPTH | TEMPORARY_RT_STENCIL)) != 0)
@@ -568,15 +568,16 @@ void Graphics::endPass()
// Resolve MSAA buffers. MSAA is only supported for 2D render targets so we
// don't have to worry about resolving to slices.
if (rts.colors.size() > 0 && rts.colors[0].canvas->getMSAA() > 1)
if (rts.colors.size() > 0 && rts.colors[0].texture->getMSAA() > 1)
{
int mip = rts.colors[0].mipmap;
int w = rts.colors[0].canvas->getPixelWidth(mip);
int h = rts.colors[0].canvas->getPixelHeight(mip);
int w = rts.colors[0].texture->getPixelWidth(mip);
int h = rts.colors[0].texture->getPixelHeight(mip);
for (int i = 0; i < (int) rts.colors.size(); i++)
{
Canvas *c = (Canvas *) rts.colors[i].canvas.get();
// FIXME
Canvas *c = (Canvas *) rts.colors[i].texture.get();
if (!c->isReadable())
continue;
@@ -619,13 +620,14 @@ void Graphics::endPass()
for (const auto &rt : rts.colors)
{
if (rt.canvas->getMipmapMode() == Canvas::MIPMAPS_AUTO && rt.mipmap == 0)
rt.canvas->generateMipmaps();
// TODO
// if (rt.texture->getMipmapMode() == Canvas::MIPMAPS_AUTO && rt.mipmap == 0)
// rt.texture->generateMipmaps();
}
int dsmipmap = rts.depthStencil.mipmap;
if (depthstencil != nullptr && depthstencil->getMipmapMode() == Canvas::MIPMAPS_AUTO && dsmipmap == 0)
depthstencil->generateMipmaps();
// int dsmipmap = rts.depthStencil.mipmap;
// if (depthstencil != nullptr && depthstencil->getMipmapMode() == Canvas::MIPMAPS_AUTO && dsmipmap == 0)
// depthstencil->generateMipmaps();
}
void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth)
@@ -818,25 +820,28 @@ void Graphics::discard(OpenGL::FramebufferTarget target, const std::vector<bool>
glDiscardFramebufferEXT(gltarget, (GLint) attachments.size(), &attachments[0]);
}
void Graphics::cleanupCanvas(Canvas *canvas)
void Graphics::cleanupCanvas(Canvas *texture)
{
if (!texture->isRenderTarget())
return;
for (auto it = framebufferObjects.begin(); it != framebufferObjects.end(); /**/)
{
bool hascanvas = false;
bool hastexture = false;
const auto &rts = it->first;
for (const RenderTarget &rt : rts.colors)
{
if (rt.canvas == canvas)
if (rt.texture == texture)
{
hascanvas = true;
hastexture = true;
break;
}
}
hascanvas = hascanvas || rts.depthStencil.canvas == canvas;
hastexture = hastexture || rts.depthStencil.texture == texture;
if (hascanvas)
if (hastexture)
{
if (isCreated())
gl.deleteFramebuffer(it->second);
@@ -857,8 +862,8 @@ void Graphics::bindCachedFBO(const RenderTargets &targets)
}
else
{
int msaa = targets.getFirstTarget().canvas->getMSAA();
bool hasDS = targets.depthStencil.canvas != nullptr;
int msaa = targets.getFirstTarget().texture->getMSAA();
bool hasDS = targets.depthStencil.texture != nullptr;
glGenFramebuffers(1, &fbo);
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, fbo);
@@ -868,9 +873,9 @@ void Graphics::bindCachedFBO(const RenderTargets &targets)
auto attachCanvas = [&](const RenderTarget &rt)
{
bool renderbuffer = msaa > 1 || !rt.canvas->isReadable();
bool renderbuffer = msaa > 1 || !rt.texture->isReadable();
bool srgb = false;
OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(rt.canvas->getPixelFormat(), renderbuffer, srgb);
OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(rt.texture->getPixelFormat(), renderbuffer, srgb);
if (fmt.framebufferAttachments[0] == GL_COLOR_ATTACHMENT0)
{
@@ -879,7 +884,7 @@ void Graphics::bindCachedFBO(const RenderTargets &targets)
ncolortargets++;
}
GLuint handle = (GLuint) rt.canvas->getRenderTargetHandle();
GLuint handle = (GLuint) rt.texture->getRenderTargetHandle();
for (GLenum attachment : fmt.framebufferAttachments)
{
@@ -889,7 +894,7 @@ void Graphics::bindCachedFBO(const RenderTargets &targets)
glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, handle);
else
{
TextureType textype = rt.canvas->getTextureType();
TextureType textype = rt.texture->getTextureType();
int layer = textype == TEXTURE_CUBE ? 0 : rt.slice;
int face = textype == TEXTURE_CUBE ? rt.slice : 0;
@@ -1056,20 +1061,20 @@ void Graphics::present(void *screenshotCallbackData)
// Reset the per-frame stat counts.
drawCalls = 0;
gl.stats.shaderSwitches = 0;
canvasSwitchCount = 0;
renderTargetSwitchCount = 0;
drawCallsBatched = 0;
// This assumes temporary canvases will only be used within a render pass.
for (int i = (int) temporaryCanvases.size() - 1; i >= 0; i--)
// This assumes temporary textures will only be used within a render pass.
for (int i = (int) temporaryTextures.size() - 1; i >= 0; i--)
{
if (temporaryCanvases[i].framesSinceUse >= MAX_TEMPORARY_CANVAS_UNUSED_FRAMES)
if (temporaryTextures[i].framesSinceUse >= MAX_TEMPORARY_TEXTURE_UNUSED_FRAMES)
{
temporaryCanvases[i].canvas->release();
temporaryCanvases[i] = temporaryCanvases.back();
temporaryCanvases.pop_back();
temporaryTextures[i].texture->release();
temporaryTextures[i] = temporaryTextures.back();
temporaryTextures.pop_back();
}
else
temporaryCanvases[i].framesSinceUse++;
temporaryTextures[i].framesSinceUse++;
}
}
@@ -1111,11 +1116,11 @@ void Graphics::setScissor()
void Graphics::drawToStencilBuffer(StencilAction action, int value)
{
const auto &rts = states.back().renderTargets;
love::graphics::Canvas *dscanvas = rts.depthStencil.canvas.get();
love::graphics::Texture *dstexture = rts.depthStencil.texture.get();
if (!isCanvasActive() && !windowHasStencil)
throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer.");
else if (isCanvasActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dscanvas == nullptr || !isPixelFormatStencil(dscanvas->getPixelFormat())))
else if (isCanvasActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat())))
throw love::Exception("Drawing to the stencil buffer with a Canvas active requires either stencil=true or a custom stencil-type Canvas to be used, in setCanvas.");
flushStreamDraws();
+1 -1
View File
@@ -126,7 +126,7 @@ private:
for (size_t i = 0; i < rts.colors.size(); i++)
hashtargets[hashcount++] = rts.colors[i];
if (rts.depthStencil.canvas != nullptr)
if (rts.depthStencil.texture != nullptr)
hashtargets[hashcount++] = rts.depthStencil;
else if (rts.temporaryRTFlags != 0)
hashtargets[hashcount++] = RenderTarget(nullptr, -1, rts.temporaryRTFlags);
+2 -18
View File
@@ -148,7 +148,7 @@ void Image::loadData()
d = std::max(d / 2, 1);
}
if (mipmapsType == MIPMAPS_GENERATED)
if (getMipmapCount() > 1 && slices.getMipmapCount() <= 1)
generateMipmaps();
}
@@ -200,22 +200,11 @@ bool Image::loadVolatile()
OpenGL::TempDebugGroup debuggroup("Image load");
if (!isCompressed())
{
// GL_EXT_sRGB doesn't support glGenerateMipmap for sRGB textures.
if (sRGB && (GLAD_ES_VERSION_2_0 && GLAD_EXT_sRGB && !GLAD_ES_VERSION_3_0)
&& mipmapsType != MIPMAPS_DATA)
{
mipmapsType = MIPMAPS_NONE;
samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE;
}
}
// NPOT textures don't support mipmapping without full NPOT support.
if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot))
&& (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight)))
{
mipmapsType = MIPMAPS_NONE;
mipmapCount = 1;
samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE;
}
@@ -231,11 +220,6 @@ bool Image::loadVolatile()
setSamplerState(samplerState);
GLenum gltextype = OpenGL::getGLTextureType(texType);
if (mipmapsType == MIPMAPS_NONE && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0))
glTexParameteri(gltextype, GL_TEXTURE_MAX_LEVEL, 0);
while (glGetError() != GL_NO_ERROR); // Clear errors.
try
+2 -2
View File
@@ -1794,10 +1794,10 @@ bool OpenGL::isPixelFormatSupported(PixelFormat pixelformat, bool rendertarget,
&& (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB));
}
else
return GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB;
return GLAD_ES_VERSION_3_0;
}
else
return GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB;
return GLAD_ES_VERSION_3_0 || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB;
case PIXELFORMAT_R16_UNORM:
case PIXELFORMAT_RG16_UNORM:
return GLAD_VERSION_3_0
+9 -9
View File
@@ -37,7 +37,7 @@ int w_Canvas_renderTo(lua_State *L)
int startidx = 2;
if (rt.canvas->getTextureType() != TEXTURE_2D)
if (rt.texture->getTextureType() != TEXTURE_2D)
{
rt.slice = (int) luaL_checkinteger(L, 2) - 1;
startidx++;
@@ -53,10 +53,10 @@ int w_Canvas_renderTo(lua_State *L)
Graphics::RenderTargets oldtargets = graphics->getCanvas();
for (auto c : oldtargets.colors)
c.canvas->retain();
c.texture->retain();
if (oldtargets.depthStencil.canvas != nullptr)
oldtargets.depthStencil.canvas->retain();
if (oldtargets.depthStencil.texture != nullptr)
oldtargets.depthStencil.texture->retain();
luax_catchexcept(L, [&](){ graphics->setCanvas(rt, false); });
@@ -66,10 +66,10 @@ int w_Canvas_renderTo(lua_State *L)
graphics->setCanvas(oldtargets);
for (auto c : oldtargets.colors)
c.canvas->release();
c.texture->release();
if (oldtargets.depthStencil.canvas != nullptr)
oldtargets.depthStencil.canvas->release();
if (oldtargets.depthStencil.texture != nullptr)
oldtargets.depthStencil.texture->release();
if (status != 0)
return lua_error(L);
@@ -119,8 +119,8 @@ int w_Canvas_getMipmapMode(lua_State *L)
{
Canvas *c = luax_checkcanvas(L, 1);
const char *str;
if (!Canvas::getConstant(c->getMipmapMode(), str))
return luax_enumerror(L, "mipmap mode", Canvas::getConstants(Canvas::MIPMAPS_MAX_ENUM), str);
if (!Texture::getConstant(c->getMipmapsMode(), str))
return luax_enumerror(L, "mipmap mode", Texture::getConstants(Texture::MIPMAPS_MAX_ENUM), str);
lua_pushstring(L, str);
return 1;
+16 -16
View File
@@ -252,7 +252,7 @@ static Graphics::RenderTarget checkRenderTarget(lua_State *L, int idx)
Graphics::RenderTarget target(luax_checkcanvas(L, -1), 0);
lua_pop(L, 1);
TextureType type = target.canvas->getTextureType();
TextureType type = target.texture->getTextureType();
if (type == TEXTURE_2D_ARRAY || type == TEXTURE_VOLUME)
target.slice = luax_checkintflag(L, idx, "layer") - 1;
else if (type == TEXTURE_CUBE)
@@ -294,7 +294,7 @@ int w_setCanvas(lua_State *L)
{
targets.colors.emplace_back(luax_checkcanvas(L, -1), 0);
if (targets.colors.back().canvas->getTextureType() != TEXTURE_2D)
if (targets.colors.back().texture->getTextureType() != TEXTURE_2D)
return luaL_error(L, "Non-2D canvases must use the table-of-tables variant of setCanvas.");
}
@@ -311,13 +311,13 @@ int w_setCanvas(lua_State *L)
else if (dstype == LUA_TBOOLEAN)
targets.temporaryRTFlags |= luax_toboolean(L, -1) ? (tempdepthflag | tempstencilflag) : 0;
else if (dstype != LUA_TNONE && dstype != LUA_TNIL)
targets.depthStencil.canvas = luax_checkcanvas(L, -1);
targets.depthStencil.texture = luax_checkcanvas(L, -1);
lua_pop(L, 1);
if (targets.depthStencil.canvas == nullptr && (targets.temporaryRTFlags & tempdepthflag) == 0)
if (targets.depthStencil.texture == nullptr && (targets.temporaryRTFlags & tempdepthflag) == 0)
targets.temporaryRTFlags |= luax_boolflag(L, 1, "depth", false) ? tempdepthflag : 0;
if (targets.depthStencil.canvas == nullptr && (targets.temporaryRTFlags & tempstencilflag) == 0)
if (targets.depthStencil.texture == nullptr && (targets.temporaryRTFlags & tempstencilflag) == 0)
targets.temporaryRTFlags |= luax_boolflag(L, 1, "stencil", false) ? tempstencilflag : 0;
}
else
@@ -325,7 +325,7 @@ int w_setCanvas(lua_State *L)
for (int i = 1; i <= lua_gettop(L); i++)
{
Graphics::RenderTarget target(luax_checkcanvas(L, i), 0);
TextureType type = target.canvas->getTextureType();
TextureType type = target.texture->getTextureType();
if (i == 1 && type != TEXTURE_2D)
{
@@ -348,7 +348,7 @@ int w_setCanvas(lua_State *L)
}
luax_catchexcept(L, [&]() {
if (targets.getFirstTarget().canvas != nullptr)
if (targets.getFirstTarget().texture != nullptr)
instance()->setCanvas(targets);
else
instance()->setCanvas();
@@ -361,10 +361,10 @@ static void pushRenderTarget(lua_State *L, const Graphics::RenderTarget &rt)
{
lua_createtable(L, 1, 2);
luax_pushtype(L, rt.canvas);
luax_pushtype(L, rt.texture);
lua_rawseti(L, -2, 1);
TextureType type = rt.canvas->getTextureType();
TextureType type = rt.texture->getTextureType();
if (type == TEXTURE_2D_ARRAY || type == TEXTURE_VOLUME)
{
@@ -392,13 +392,13 @@ int w_getCanvas(lua_State *L)
return 1;
}
bool shouldUseTablesVariant = targets.depthStencil.canvas != nullptr;
bool shouldUseTablesVariant = targets.depthStencil.texture != nullptr;
if (!shouldUseTablesVariant)
{
for (const auto &rt : targets.colors)
{
if (rt.mipmap != 0 || rt.canvas->getTextureType() != TEXTURE_2D)
if (rt.mipmap != 0 || rt.texture->getTextureType() != TEXTURE_2D)
{
shouldUseTablesVariant = true;
break;
@@ -416,7 +416,7 @@ int w_getCanvas(lua_State *L)
lua_rawseti(L, -2, i + 1);
}
if (targets.depthStencil.canvas != nullptr)
if (targets.depthStencil.texture != nullptr)
{
pushRenderTarget(L, targets.depthStencil);
lua_setfield(L, -2, "depthstencil");
@@ -427,7 +427,7 @@ int w_getCanvas(lua_State *L)
else
{
for (const auto &rt : targets.colors)
luax_pushtype(L, rt.canvas);
luax_pushtype(L, rt.texture);
return ntargets;
}
@@ -1240,8 +1240,8 @@ int w_newCanvas(lua_State *L)
if (!lua_isnoneornil(L, -1))
{
const char *str = luaL_checkstring(L, -1);
if (!Canvas::getConstant(str, settings.mipmaps))
return luax_enumerror(L, "Canvas mipmap mode", Canvas::getConstants(settings.mipmaps), str);
if (!Texture::getConstant(str, settings.mipmaps))
return luax_enumerror(L, "Texture mipmap mode", Texture::getConstants(settings.mipmaps), str);
}
lua_pop(L, 1);
}
@@ -2388,7 +2388,7 @@ int w_getStats(lua_State *L)
lua_pushinteger(L, stats.drawCallsBatched);
lua_setfield(L, -2, "drawcallsbatched");
lua_pushinteger(L, stats.canvasSwitches);
lua_pushinteger(L, stats.renderTargetSwitches);
lua_setfield(L, -2, "canvasswitches");
lua_pushinteger(L, stats.shaderSwitches);
+1 -1
View File
@@ -40,7 +40,7 @@ int w_Image_replacePixels(lua_State *L)
int mipmap = 0;
int x = 0;
int y = 0;
bool reloadmipmaps = i->getMipmapsType() == Image::MIPMAPS_GENERATED;
bool reloadmipmaps = false; // TODO i->getMipmapsSource() == Texture::MIPMAPS_SOURCE_GENERATED;
if (i->getTextureType() != TEXTURE_2D)
slice = (int) luaL_checkinteger(L, 3) - 1;