mirror of
https://github.com/love2d/love.git
synced 2026-08-19 20:19:42 +02:00
Allow a temporary/internal depth buffer to be used when a Canvas is active, similar to how temporary stencil buffers are allowed.
Syntax is setCanvas{canvas [, depth=true, stencil=true]} or setCanvas{canvas, depthstencil=true}.
--HG--
branch : minor
This commit is contained in:
@@ -315,7 +315,7 @@ void Graphics::restoreStateChecked(const DisplayState &s)
|
|||||||
canvaseschanged = true;
|
canvaseschanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sRTs.useTemporaryStencil != curRTs.useTemporaryStencil)
|
if (sRTs.temporaryRTFlags != curRTs.temporaryRTFlags)
|
||||||
canvaseschanged = true;
|
canvaseschanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,14 +403,14 @@ love::graphics::Shader *Graphics::getShader() const
|
|||||||
return states.back().shader.get();
|
return states.back().shader.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::setCanvas(RenderTarget rt, bool useStencil)
|
void Graphics::setCanvas(RenderTarget rt, uint32 temporaryRTFlags)
|
||||||
{
|
{
|
||||||
if (rt.canvas == nullptr)
|
if (rt.canvas == nullptr)
|
||||||
return setCanvas();
|
return setCanvas();
|
||||||
|
|
||||||
RenderTargets rts;
|
RenderTargets rts;
|
||||||
rts.colors.push_back(rt);
|
rts.colors.push_back(rt);
|
||||||
rts.useTemporaryStencil = useStencil;
|
rts.temporaryRTFlags = temporaryRTFlags;
|
||||||
|
|
||||||
setCanvas(rts);
|
setCanvas(rts);
|
||||||
}
|
}
|
||||||
@@ -424,7 +424,7 @@ void Graphics::setCanvas(const RenderTargetsStrongRef &rts)
|
|||||||
targets.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap);
|
targets.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap);
|
||||||
|
|
||||||
targets.depthStencil = RenderTarget(rts.depthStencil.canvas, rts.depthStencil.slice, rts.depthStencil.mipmap);
|
targets.depthStencil = RenderTarget(rts.depthStencil.canvas, rts.depthStencil.slice, rts.depthStencil.mipmap);
|
||||||
targets.useTemporaryStencil = rts.useTemporaryStencil;
|
targets.temporaryRTFlags = rts.temporaryRTFlags;
|
||||||
|
|
||||||
return setCanvas(targets);
|
return setCanvas(targets);
|
||||||
}
|
}
|
||||||
@@ -440,7 +440,7 @@ Graphics::RenderTargets Graphics::getCanvas() const
|
|||||||
rts.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap);
|
rts.colors.emplace_back(rt.canvas.get(), rt.slice, rt.mipmap);
|
||||||
|
|
||||||
rts.depthStencil = RenderTarget(curRTs.depthStencil.canvas, curRTs.depthStencil.slice, curRTs.depthStencil.mipmap);
|
rts.depthStencil = RenderTarget(curRTs.depthStencil.canvas, curRTs.depthStencil.slice, curRTs.depthStencil.mipmap);
|
||||||
rts.useTemporaryStencil = curRTs.useTemporaryStencil;
|
rts.temporaryRTFlags = curRTs.temporaryRTFlags;
|
||||||
|
|
||||||
return rts;
|
return rts;
|
||||||
}
|
}
|
||||||
@@ -483,6 +483,36 @@ bool Graphics::isCanvasActive(Canvas *canvas, int slice) const
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Canvas *Graphics::getTemporaryCanvas(PixelFormat format, int w, int h, int samples)
|
||||||
|
{
|
||||||
|
love::graphics::Canvas *canvas = nullptr;
|
||||||
|
|
||||||
|
for (Canvas *c : temporaryCanvases)
|
||||||
|
{
|
||||||
|
if (c->getPixelFormat() == format && c->getPixelWidth() == w
|
||||||
|
&& c->getPixelHeight() == h && c->getRequestedMSAA() == samples)
|
||||||
|
{
|
||||||
|
canvas = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canvas == nullptr)
|
||||||
|
{
|
||||||
|
Canvas::Settings settings;
|
||||||
|
settings.format = format;
|
||||||
|
settings.width = w;
|
||||||
|
settings.height = h;
|
||||||
|
settings.msaa = samples;
|
||||||
|
|
||||||
|
canvas = newCanvas(settings);
|
||||||
|
|
||||||
|
temporaryCanvases.push_back(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
void Graphics::intersectScissor(const Rect &rect)
|
void Graphics::intersectScissor(const Rect &rect)
|
||||||
{
|
{
|
||||||
Rect currect = states.back().scissorRect;
|
Rect currect = states.back().scissorRect;
|
||||||
|
|||||||
@@ -193,6 +193,12 @@ public:
|
|||||||
STACK_MAX_ENUM
|
STACK_MAX_ENUM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum TemporaryRenderTargetFlags
|
||||||
|
{
|
||||||
|
TEMPORARY_RT_DEPTH = (1 << 0),
|
||||||
|
TEMPORARY_RT_STENCIL = (1 << 1),
|
||||||
|
};
|
||||||
|
|
||||||
struct RendererInfo
|
struct RendererInfo
|
||||||
{
|
{
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -325,11 +331,11 @@ public:
|
|||||||
{
|
{
|
||||||
std::vector<RenderTarget> colors;
|
std::vector<RenderTarget> colors;
|
||||||
RenderTarget depthStencil;
|
RenderTarget depthStencil;
|
||||||
bool useTemporaryStencil;
|
uint32 temporaryRTFlags;
|
||||||
|
|
||||||
RenderTargets()
|
RenderTargets()
|
||||||
: depthStencil(nullptr)
|
: depthStencil(nullptr)
|
||||||
, useTemporaryStencil(false)
|
, temporaryRTFlags(0)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -337,11 +343,11 @@ public:
|
|||||||
{
|
{
|
||||||
std::vector<RenderTargetStrongRef> colors;
|
std::vector<RenderTargetStrongRef> colors;
|
||||||
RenderTargetStrongRef depthStencil;
|
RenderTargetStrongRef depthStencil;
|
||||||
bool useTemporaryStencil;
|
uint32 temporaryRTFlags;
|
||||||
|
|
||||||
RenderTargetsStrongRef()
|
RenderTargetsStrongRef()
|
||||||
: depthStencil(nullptr)
|
: depthStencil(nullptr)
|
||||||
, useTemporaryStencil(false)
|
, temporaryRTFlags(0)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -465,7 +471,7 @@ public:
|
|||||||
|
|
||||||
Shader *getShader() const;
|
Shader *getShader() const;
|
||||||
|
|
||||||
void setCanvas(RenderTarget rt, bool useStencil);
|
void setCanvas(RenderTarget rt, uint32 temporaryRTFlags);
|
||||||
virtual void setCanvas(const RenderTargets &rts) = 0;
|
virtual void setCanvas(const RenderTargets &rts) = 0;
|
||||||
void setCanvas(const RenderTargetsStrongRef &rts);
|
void setCanvas(const RenderTargetsStrongRef &rts);
|
||||||
virtual void setCanvas() = 0;
|
virtual void setCanvas() = 0;
|
||||||
@@ -860,6 +866,8 @@ protected:
|
|||||||
|
|
||||||
virtual void getAPIStats(int &drawcalls, int &shaderswitches) const = 0;
|
virtual void getAPIStats(int &drawcalls, int &shaderswitches) const = 0;
|
||||||
|
|
||||||
|
Canvas *getTemporaryCanvas(PixelFormat format, int w, int h, int samples);
|
||||||
|
|
||||||
void restoreState(const DisplayState &s);
|
void restoreState(const DisplayState &s);
|
||||||
void restoreStateChecked(const DisplayState &s);
|
void restoreStateChecked(const DisplayState &s);
|
||||||
|
|
||||||
@@ -891,6 +899,8 @@ protected:
|
|||||||
std::vector<DisplayState> states;
|
std::vector<DisplayState> states;
|
||||||
std::vector<StackType> stackTypeStack;
|
std::vector<StackType> stackTypeStack;
|
||||||
|
|
||||||
|
std::vector<Canvas *> temporaryCanvases;
|
||||||
|
|
||||||
int canvasSwitchCount;
|
int canvasSwitchCount;
|
||||||
|
|
||||||
static const size_t MAX_USER_STACK_DEPTH = 64;
|
static const size_t MAX_USER_STACK_DEPTH = 64;
|
||||||
|
|||||||
@@ -120,13 +120,9 @@ void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color c = toColor(gfx->getColor());
|
|
||||||
|
|
||||||
const Matrix4 &tm = gfx->getTransform();
|
const Matrix4 &tm = gfx->getTransform();
|
||||||
bool is2D = tm.isAffine2DTransform();
|
bool is2D = tm.isAffine2DTransform();
|
||||||
|
|
||||||
Matrix4 t(tm, localTransform);
|
|
||||||
|
|
||||||
Graphics::StreamDrawRequest req;
|
Graphics::StreamDrawRequest req;
|
||||||
req.formats[0] = vertex::getSinglePositionFormat(is2D);
|
req.formats[0] = vertex::getSinglePositionFormat(is2D);
|
||||||
req.formats[1] = CommonFormat::STf_RGBAub;
|
req.formats[1] = CommonFormat::STf_RGBAub;
|
||||||
@@ -136,6 +132,8 @@ void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform)
|
|||||||
|
|
||||||
Graphics::StreamVertexData data = gfx->requestStreamDraw(req);
|
Graphics::StreamVertexData data = gfx->requestStreamDraw(req);
|
||||||
|
|
||||||
|
Matrix4 t(tm, localTransform);
|
||||||
|
|
||||||
if (is2D)
|
if (is2D)
|
||||||
t.transformXY((Vector2 *) data.stream[0], q->getVertexPositions(), 4);
|
t.transformXY((Vector2 *) data.stream[0], q->getVertexPositions(), 4);
|
||||||
else
|
else
|
||||||
@@ -144,6 +142,8 @@ void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform)
|
|||||||
const Vector2 *texcoords = q->getVertexTexCoords();
|
const Vector2 *texcoords = q->getVertexTexCoords();
|
||||||
vertex::STf_RGBAub *vertexdata = (vertex::STf_RGBAub *) data.stream[1];
|
vertex::STf_RGBAub *vertexdata = (vertex::STf_RGBAub *) data.stream[1];
|
||||||
|
|
||||||
|
Color c = toColor(gfx->getColor());
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
vertexdata[i].s = texcoords[i].x;
|
vertexdata[i].s = texcoords[i].x;
|
||||||
|
|||||||
@@ -301,11 +301,11 @@ void Graphics::unSetMode()
|
|||||||
for (const auto &pair : framebufferObjects)
|
for (const auto &pair : framebufferObjects)
|
||||||
gl.deleteFramebuffer(pair.second);
|
gl.deleteFramebuffer(pair.second);
|
||||||
|
|
||||||
for (love::graphics::Canvas *c : stencilBuffers)
|
for (auto c : temporaryCanvases)
|
||||||
c->release();
|
c->release();
|
||||||
|
|
||||||
framebufferObjects.clear();
|
framebufferObjects.clear();
|
||||||
stencilBuffers.clear();
|
temporaryCanvases.clear();
|
||||||
|
|
||||||
if (mainVAO != 0)
|
if (mainVAO != 0)
|
||||||
{
|
{
|
||||||
@@ -513,7 +513,7 @@ void Graphics::setCanvas(const RenderTargets &rts)
|
|||||||
modified = true;
|
modified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rts.useTemporaryStencil != prevRTs.useTemporaryStencil)
|
if (rts.temporaryRTFlags != prevRTs.temporaryRTFlags)
|
||||||
modified = true;
|
modified = true;
|
||||||
|
|
||||||
if (!modified)
|
if (!modified)
|
||||||
@@ -614,7 +614,7 @@ void Graphics::setCanvas(const RenderTargets &rts)
|
|||||||
refs.colors.emplace_back(c.canvas, c.slice);
|
refs.colors.emplace_back(c.canvas, c.slice);
|
||||||
|
|
||||||
refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.canvas, rts.depthStencil.slice);
|
refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.canvas, rts.depthStencil.slice);
|
||||||
refs.useTemporaryStencil = rts.useTemporaryStencil;
|
refs.temporaryRTFlags = rts.temporaryRTFlags;
|
||||||
|
|
||||||
std::swap(state.renderTargets, refs);
|
std::swap(state.renderTargets, refs);
|
||||||
|
|
||||||
@@ -665,8 +665,8 @@ void Graphics::endPass()
|
|||||||
auto &rts = states.back().renderTargets;
|
auto &rts = states.back().renderTargets;
|
||||||
love::graphics::Canvas *depthstencil = rts.depthStencil.canvas.get();
|
love::graphics::Canvas *depthstencil = rts.depthStencil.canvas.get();
|
||||||
|
|
||||||
// Discard the stencil buffer if we're using an internal cached one.
|
// Discard the depth/stencil buffer if we're using an internal cached one.
|
||||||
if (depthstencil == nullptr && rts.useTemporaryStencil)
|
if (depthstencil == nullptr && (rts.temporaryRTFlags & (TEMPORARY_RT_DEPTH | TEMPORARY_RT_STENCIL)) != 0)
|
||||||
discard({}, true);
|
discard({}, true);
|
||||||
|
|
||||||
// Resolve MSAA buffers. MSAA is only supported for 2D render targets so we
|
// Resolve MSAA buffers. MSAA is only supported for 2D render targets so we
|
||||||
@@ -891,8 +891,8 @@ void Graphics::bindCachedFBO(const RenderTargets &targets)
|
|||||||
|
|
||||||
if (targets.depthStencil.canvas != nullptr)
|
if (targets.depthStencil.canvas != nullptr)
|
||||||
hashtargets[hashcount++] = targets.depthStencil;
|
hashtargets[hashcount++] = targets.depthStencil;
|
||||||
else if (targets.useTemporaryStencil)
|
else if (targets.temporaryRTFlags != 0)
|
||||||
hashtargets[hashcount++] = RenderTarget(nullptr, -1, 0);
|
hashtargets[hashcount++] = RenderTarget(nullptr, -1, targets.temporaryRTFlags);
|
||||||
|
|
||||||
uint32 hash = XXH32(hashtargets, sizeof(RenderTarget) * hashcount, 0);
|
uint32 hash = XXH32(hashtargets, sizeof(RenderTarget) * hashcount, 0);
|
||||||
GLuint fbo = framebufferObjects[hash];
|
GLuint fbo = framebufferObjects[hash];
|
||||||
@@ -911,9 +911,22 @@ void Graphics::bindCachedFBO(const RenderTargets &targets)
|
|||||||
|
|
||||||
RenderTarget depthstencil = targets.depthStencil;
|
RenderTarget depthstencil = targets.depthStencil;
|
||||||
|
|
||||||
if (depthstencil.canvas == nullptr && targets.useTemporaryStencil)
|
if (depthstencil.canvas == nullptr && targets.temporaryRTFlags != 0)
|
||||||
{
|
{
|
||||||
depthstencil.canvas = getCachedStencilBuffer(w, h, reqmsaa);
|
bool wantsdepth = (targets.temporaryRTFlags & TEMPORARY_RT_DEPTH) != 0;
|
||||||
|
bool wantsstencil = (targets.temporaryRTFlags & TEMPORARY_RT_STENCIL) != 0;
|
||||||
|
|
||||||
|
PixelFormat dsformat = PIXELFORMAT_STENCIL8;
|
||||||
|
if (wantsdepth && wantsstencil)
|
||||||
|
dsformat = PIXELFORMAT_DEPTH24_STENCIL8;
|
||||||
|
else if (wantsdepth && isCanvasFormatSupported(PIXELFORMAT_DEPTH24, false))
|
||||||
|
dsformat = PIXELFORMAT_DEPTH24;
|
||||||
|
else if (wantsdepth)
|
||||||
|
dsformat = PIXELFORMAT_DEPTH16;
|
||||||
|
else if (wantsstencil)
|
||||||
|
dsformat = PIXELFORMAT_STENCIL8;
|
||||||
|
|
||||||
|
depthstencil.canvas = getTemporaryCanvas(dsformat, w, h, reqmsaa);
|
||||||
depthstencil.slice = 0;
|
depthstencil.slice = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -979,35 +992,6 @@ void Graphics::bindCachedFBO(const RenderTargets &targets)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
love::graphics::Canvas *Graphics::getCachedStencilBuffer(int w, int h, int samples)
|
|
||||||
{
|
|
||||||
love::graphics::Canvas *canvas = nullptr;
|
|
||||||
|
|
||||||
for (love::graphics::Canvas *c : stencilBuffers)
|
|
||||||
{
|
|
||||||
if (c->getPixelWidth() == w && c->getPixelHeight() == h && c->getRequestedMSAA() == samples)
|
|
||||||
{
|
|
||||||
canvas = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canvas == nullptr)
|
|
||||||
{
|
|
||||||
Canvas::Settings settings;
|
|
||||||
settings.format = PIXELFORMAT_STENCIL8;
|
|
||||||
settings.width = w;
|
|
||||||
settings.height = h;
|
|
||||||
settings.msaa = samples;
|
|
||||||
|
|
||||||
canvas = newCanvas(settings);
|
|
||||||
|
|
||||||
stencilBuffers.push_back(canvas);
|
|
||||||
}
|
|
||||||
|
|
||||||
return canvas;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Graphics::present(void *screenshotCallbackData)
|
void Graphics::present(void *screenshotCallbackData)
|
||||||
{
|
{
|
||||||
if (!isActive())
|
if (!isActive())
|
||||||
@@ -1167,7 +1151,7 @@ void Graphics::drawToStencilBuffer(StencilAction action, int value)
|
|||||||
|
|
||||||
if (!isCanvasActive() && !windowHasStencil)
|
if (!isCanvasActive() && !windowHasStencil)
|
||||||
throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer.");
|
throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer.");
|
||||||
else if (isCanvasActive() && !rts.useTemporaryStencil && (dscanvas == nullptr || !isPixelFormatStencil(dscanvas->getPixelFormat())))
|
else if (isCanvasActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dscanvas == nullptr || !isPixelFormatStencil(dscanvas->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.");
|
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();
|
flushStreamDraws();
|
||||||
|
|||||||
@@ -137,17 +137,12 @@ private:
|
|||||||
void endPass();
|
void endPass();
|
||||||
void bindCachedFBO(const RenderTargets &targets);
|
void bindCachedFBO(const RenderTargets &targets);
|
||||||
void discard(OpenGL::FramebufferTarget target, const std::vector<bool> &colorbuffers, bool depthstencil);
|
void discard(OpenGL::FramebufferTarget target, const std::vector<bool> &colorbuffers, bool depthstencil);
|
||||||
love::graphics::Canvas *getCachedStencilBuffer(int w, int h, int samples);
|
|
||||||
|
|
||||||
void setDebug(bool enable);
|
void setDebug(bool enable);
|
||||||
|
|
||||||
std::unordered_map<uint32, GLuint> framebufferObjects;
|
std::unordered_map<uint32, GLuint> framebufferObjects;
|
||||||
std::vector<love::graphics::Canvas *> stencilBuffers;
|
|
||||||
|
|
||||||
QuadIndices *quadIndices;
|
QuadIndices *quadIndices;
|
||||||
|
|
||||||
bool windowHasStencil;
|
bool windowHasStencil;
|
||||||
|
|
||||||
GLuint mainVAO;
|
GLuint mainVAO;
|
||||||
|
|
||||||
}; // Graphics
|
}; // Graphics
|
||||||
|
|||||||
@@ -294,15 +294,23 @@ int w_setCanvas(lua_State *L)
|
|||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32 tempdepthflag = Graphics::TEMPORARY_RT_DEPTH;
|
||||||
|
uint32 tempstencilflag = Graphics::TEMPORARY_RT_STENCIL;
|
||||||
|
|
||||||
lua_getfield(L, 1, "depthstencil");
|
lua_getfield(L, 1, "depthstencil");
|
||||||
if (lua_istable(L, -1))
|
if (lua_istable(L, -1))
|
||||||
targets.depthStencil = checkRenderTarget(L, -1);
|
targets.depthStencil = checkRenderTarget(L, -1);
|
||||||
|
else if (lua_isboolean(L, -1))
|
||||||
|
targets.temporaryRTFlags |= luax_toboolean(L, -1) ? (tempdepthflag | tempstencilflag) : 0;
|
||||||
else if (!lua_isnoneornil(L, -1))
|
else if (!lua_isnoneornil(L, -1))
|
||||||
targets.depthStencil.canvas = luax_checkcanvas(L, -1);
|
targets.depthStencil.canvas = luax_checkcanvas(L, -1);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
|
|
||||||
if (targets.depthStencil.canvas == nullptr)
|
if (targets.depthStencil.canvas == nullptr && (targets.temporaryRTFlags & tempdepthflag) == 0)
|
||||||
targets.useTemporaryStencil = luax_boolflag(L, 1, "stencil", false);
|
targets.temporaryRTFlags |= luax_boolflag(L, 1, "depth", false) ? tempdepthflag : 0;
|
||||||
|
|
||||||
|
if (targets.depthStencil.canvas == nullptr && (targets.temporaryRTFlags & tempstencilflag) == 0)
|
||||||
|
targets.temporaryRTFlags |= luax_boolflag(L, 1, "stencil", false) ? tempstencilflag : 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user