renderer: ++engines safety

Added drawing exceptions when target is not properly ready.

Now, Canvas::update() Canvas::draw() will return InsufficientCondition
if the target has not been set beforehand.
This commit is contained in:
Hermet Park 2025-05-12 11:50:52 +09:00 committed by Hermet Park
parent 2524cdfee5
commit 3fbb55440a
9 changed files with 32 additions and 5 deletions

View file

@ -40,8 +40,9 @@ GlRenderTarget::~GlRenderTarget()
void GlRenderTarget::init(GLint resolveId) void GlRenderTarget::init(GLint resolveId)
{ {
if (mFbo != 0 || mWidth == 0 || mHeight == 0) return; if (mFbo != GL_INVALID_VALUE || mWidth == 0 || mHeight == 0) return;
//TODO: fbo is used. maybe we can consider the direct rendering with resolveId as well.
GL_CHECK(glGenFramebuffers(1, &mFbo)); GL_CHECK(glGenFramebuffers(1, &mFbo));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mFbo)); GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mFbo));

View file

@ -44,12 +44,13 @@ public:
void setViewport(const RenderRegion& vp) { mViewport = vp; } void setViewport(const RenderRegion& vp) { mViewport = vp; }
const RenderRegion& getViewport() const { return mViewport; } const RenderRegion& getViewport() const { return mViewport; }
bool invalid() const { return mFbo == GL_INVALID_VALUE; }
private: private:
uint32_t mWidth = 0; uint32_t mWidth = 0;
uint32_t mHeight = 0; uint32_t mHeight = 0;
RenderRegion mViewport{}; RenderRegion mViewport{};
GLuint mFbo = 0; GLuint mFbo = GL_INVALID_VALUE;
GLuint mColorBuffer = 0; GLuint mColorBuffer = 0;
GLuint mDepthStencilBuffer = 0; GLuint mDepthStencilBuffer = 0;
GLuint mResolveFbo = 0; GLuint mResolveFbo = 0;

View file

@ -809,6 +809,8 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp)
bool GlRenderer::clear() bool GlRenderer::clear()
{ {
if (mRootTarget.invalid()) return false;
mClearBuffer = true; mClearBuffer = true;
return true; return true;
} }
@ -896,6 +898,8 @@ RenderRegion GlRenderer::region(RenderData data)
bool GlRenderer::preRender() bool GlRenderer::preRender()
{ {
if (mRootTarget.invalid()) return false;
currentContext(); currentContext();
if (mPrograms.empty()) initShaders(); if (mPrograms.empty()) initShaders();
mRenderPassStack.push(new GlRenderPass(&mRootTarget)); mRenderPassStack.push(new GlRenderPass(&mRootTarget));
@ -1525,6 +1529,8 @@ bool GlRenderer::viewport(const RenderRegion& vp)
bool GlRenderer::preUpdate() bool GlRenderer::preUpdate()
{ {
if (mRootTarget.invalid()) return false;
currentContext(); currentContext();
return true; return true;
} }

View file

@ -359,7 +359,7 @@ bool SwRenderer::target(pixel_t* data, uint32_t stride, uint32_t w, uint32_t h,
bool SwRenderer::preUpdate() bool SwRenderer::preUpdate()
{ {
return true; return surface != nullptr;
} }
@ -371,7 +371,7 @@ bool SwRenderer::postUpdate()
bool SwRenderer::preRender() bool SwRenderer::preRender()
{ {
return true; return surface != nullptr;
} }

View file

@ -70,6 +70,11 @@ struct WgContext {
// release buffer objects // release buffer objects
void releaseBuffer(WGPUBuffer& buffer); void releaseBuffer(WGPUBuffer& buffer);
bool invalid()
{
return !instance || !device;
}
}; };
#endif // _TVG_WG_COMMON_H_ #endif // _TVG_WG_COMMON_H_

View file

@ -195,6 +195,8 @@ RenderData WgRenderer::prepare(RenderSurface* surface, RenderData data, const Ma
bool WgRenderer::preRender() bool WgRenderer::preRender()
{ {
if (mContext.invalid()) return false;
// push rot render storage to the render tree stack // push rot render storage to the render tree stack
assert(mRenderStorageStack.count == 0); assert(mRenderStorageStack.count == 0);
mRenderStorageStack.push(&mRenderStorageRoot); mRenderStorageStack.push(&mRenderStorageRoot);
@ -301,6 +303,8 @@ const RenderSurface* WgRenderer::mainSurface()
bool WgRenderer::clear() bool WgRenderer::clear()
{ {
if (mContext.invalid()) return false;
//TODO: clear the current target buffer only if clear() is called //TODO: clear the current target buffer only if clear() is called
return true; return true;
} }
@ -632,6 +636,8 @@ void WgRenderer::dispose(RenderEffect* effect)
bool WgRenderer::preUpdate() bool WgRenderer::preUpdate()
{ {
if (mContext.invalid()) return false;
return true; return true;
} }

View file

@ -121,6 +121,9 @@ TEST_CASE("Bounding Box", "[tvgPaint]")
Initializer::init(0); Initializer::init(0);
auto canvas = unique_ptr<SwCanvas>(SwCanvas::gen()); auto canvas = unique_ptr<SwCanvas>(SwCanvas::gen());
uint32_t buffer[100*100];
canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888);
auto shape = Shape::gen(); auto shape = Shape::gen();
canvas->push(shape); canvas->push(shape);
canvas->sync(); canvas->sync();

View file

@ -80,7 +80,8 @@ TEST_CASE("Scene Clear And Reuse Shape", "[tvgScene]")
REQUIRE(Initializer::init(0) == Result::Success); REQUIRE(Initializer::init(0) == Result::Success);
{ {
auto canvas = unique_ptr<SwCanvas>(SwCanvas::gen()); auto canvas = unique_ptr<SwCanvas>(SwCanvas::gen());
REQUIRE(canvas); uint32_t buffer[100*100];
canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888);
auto scene = Scene::gen(); auto scene = Scene::gen();
REQUIRE(scene); REQUIRE(scene);

View file

@ -120,6 +120,8 @@ TEST_CASE("Text Basic", "[tvgText]")
Initializer::init(0); Initializer::init(0);
auto canvas = unique_ptr<SwCanvas>(SwCanvas::gen()); auto canvas = unique_ptr<SwCanvas>(SwCanvas::gen());
uint32_t buffer[100*100];
canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888);
auto text = Text::gen(); auto text = Text::gen();
REQUIRE(text); REQUIRE(text);
@ -144,6 +146,8 @@ TEST_CASE("Text with composite glyphs", "[tvgText]")
Initializer::init(0); Initializer::init(0);
auto canvas = unique_ptr<SwCanvas>(SwCanvas::gen()); auto canvas = unique_ptr<SwCanvas>(SwCanvas::gen());
uint32_t buffer[100*100];
canvas->target(buffer, 100, 100, 100, ColorSpace::ABGR8888);
auto text = Text::gen(); auto text = Text::gen();
REQUIRE(text); REQUIRE(text);