renderer/engines: redesigned RenderRegion property layout

redefiend properties so that min/max are prioritized,
as they are accessed more frequently than pos/size
during rendering calculations.

also introduced miscellaneous functions to improve usability.
This commit is contained in:
Hermet Park 2025-05-06 16:40:32 +09:00 committed by Hermet Park
parent 04b7bb4f25
commit 8a35f02105
24 changed files with 406 additions and 428 deletions

View file

@ -57,55 +57,52 @@ bool GlGeometry::tesselate(const RenderShape& rshape, RenderUpdateFlag flag)
bool GlGeometry::tesselate(const RenderSurface* image, RenderUpdateFlag flag)
{
if (flag & RenderUpdateFlag::Image) {
fill.clear();
if (!(flag & RenderUpdateFlag::Image)) return true;
fill.vertex.reserve(5 * 4);
fill.index.reserve(6);
fill.clear();
float left = 0.f;
float top = 0.f;
float right = image->w;
float bottom = image->h;
fill.vertex.reserve(5 * 4);
fill.index.reserve(6);
// left top point
fill.vertex.push(left);
fill.vertex.push(top);
auto left = 0.f;
auto top = 0.f;
auto right = float(image->w);
auto bottom = float(image->h);
fill.vertex.push(0.f);
fill.vertex.push(1.f);
// left bottom point
fill.vertex.push(left);
fill.vertex.push(bottom);
// left top point
fill.vertex.push(left);
fill.vertex.push(top);
fill.vertex.push(0.f);
fill.vertex.push(0.f);
// right top point
fill.vertex.push(right);
fill.vertex.push(top);
fill.vertex.push(0.f);
fill.vertex.push(1.f);
// left bottom point
fill.vertex.push(left);
fill.vertex.push(bottom);
fill.vertex.push(1.f);
fill.vertex.push(1.f);
// right bottom point
fill.vertex.push(right);
fill.vertex.push(bottom);
fill.vertex.push(0.f);
fill.vertex.push(0.f);
// right top point
fill.vertex.push(right);
fill.vertex.push(top);
fill.vertex.push(1.f);
fill.vertex.push(0.f);
fill.vertex.push(1.f);
fill.vertex.push(1.f);
// right bottom point
fill.vertex.push(right);
fill.vertex.push(bottom);
fill.index.push(0);
fill.index.push(1);
fill.index.push(2);
fill.vertex.push(1.f);
fill.vertex.push(0.f);
fill.index.push(2);
fill.index.push(1);
fill.index.push(3);
fill.index.push(0);
fill.index.push(1);
fill.index.push(2);
bounds.x = 0;
bounds.y = 0;
bounds.w = image->w;
bounds.h = image->h;
}
fill.index.push(2);
fill.index.push(1);
fill.index.push(3);
bounds = {{0, 0}, {int32_t(image->w), int32_t(image->h)}};
return true;
}
@ -155,31 +152,20 @@ GlStencilMode GlGeometry::getStencilMode(RenderUpdateFlag flag)
RenderRegion GlGeometry::getBounds() const
{
if (tvg::identity(&matrix)) {
return bounds;
} else {
Point lt{static_cast<float>(bounds.x), static_cast<float>(bounds.y)};
Point lb{static_cast<float>(bounds.x), static_cast<float>(bounds.y + bounds.h)};
Point rt{static_cast<float>(bounds.x + bounds.w), static_cast<float>(bounds.y)};
Point rb{static_cast<float>(bounds.x + bounds.w), static_cast<float>(bounds.y + bounds.h)};
if (tvg::identity(&matrix)) return bounds;
lt *= matrix;
lb *= matrix;
rt *= matrix;
rb *= matrix;
auto lt = Point{float(bounds.min.x), float(bounds.min.y)} * matrix;
auto lb = Point{float(bounds.min.x), float(bounds.max.y)} * matrix;
auto rt = Point{float(bounds.max.x), float(bounds.min.y)} * matrix;
auto rb = Point{float(bounds.max.x), float(bounds.max.y)} * matrix;
float left = min(min(lt.x, lb.x), min(rt.x, rb.x));
float top = min(min(lt.y, lb.y), min(rt.y, rb.y));
float right = max(max(lt.x, lb.x), max(rt.x, rb.x));
float bottom = max(max(lt.y, lb.y), max(rt.y, rb.y));
auto left = min(min(lt.x, lb.x), min(rt.x, rb.x));
auto top = min(min(lt.y, lb.y), min(rt.y, rb.y));
auto right = max(max(lt.x, lb.x), max(rt.x, rb.x));
auto bottom = max(max(lt.y, lb.y), max(rt.y, rb.y));
auto bounds = RenderRegion {{int32_t(floor(left)), int32_t(floor(top))}, {int32_t(ceil(right)), int32_t(ceil(bottom))}};
if (bounds.valid()) return bounds;
return this->bounds;
auto bounds = RenderRegion {
static_cast<int32_t>(floor(left)),
static_cast<int32_t>(floor(top)),
static_cast<int32_t>(ceil(right - floor(left))),
static_cast<int32_t>(ceil(bottom - floor(top))),
};
if (bounds.w < 0 || bounds.h < 0) return this->bounds;
else return bounds;
}
}

View file

@ -52,17 +52,17 @@ void GlRenderPass::addRenderTask(GlRenderTask* task)
void GlRenderPass::getMatrix(float *dst, const Matrix &matrix) const
{
const auto& vp = getViewport();
Matrix postMatrix{};
tvg::identity(&postMatrix);
translate(&postMatrix, {(float)-vp.x, (float)-vp.y});
const auto& vp = getViewport();
translate(&postMatrix, {(float)-vp.sx(), (float)-vp.sy()});
auto m = postMatrix * matrix;
float modelMatrix[16];
GET_MATRIX44(m, modelMatrix);
MVP_MATRIX(vp.w, vp.h);
MVP_MATRIX(vp.w(), vp.h());
MULTIPLY_MATRIX(mvp, modelMatrix, dst);
}

View file

@ -62,10 +62,7 @@ public:
}
auto task = new T(program, targetFbo, mFbo, std::move(mTasks));
const auto& vp = mFbo->getViewport();
task->setRenderSize(static_cast<uint32_t>(vp.w), static_cast<uint32_t>(vp.h));
task->setRenderSize(mFbo->getViewport().w(), mFbo->getViewport().h());
return task;
}

View file

@ -107,23 +107,20 @@ uint32_t alignPow2(uint32_t value)
GlRenderTarget* GlRenderTargetPool::getRenderTarget(const RenderRegion& vp, GLuint resolveId)
{
uint32_t width = static_cast<uint32_t>(vp.w);
uint32_t height = static_cast<uint32_t>(vp.h);
auto width = vp.w();
auto height = vp.h();
// pow2 align width and height
if (width >= mMaxWidth) width = mMaxWidth;
else width = alignPow2(width);
if (width >= mMaxWidth) width = mMaxWidth;
if (height >= mMaxHeight) height = mMaxHeight;
else height = alignPow2(height);
if (height >= mMaxHeight) height = mMaxHeight;
for (uint32_t i = 0; i < mPool.count; i++) {
auto rt = mPool[i];
if (rt->getWidth() == width && rt->getHeight() == height) {
rt->setViewport(vp);
return rt;

View file

@ -24,6 +24,9 @@
#include "tvgGlProgram.h"
#include "tvgGlRenderPass.h"
/************************************************************************/
/* GlRenderTask Class Implementation */
/************************************************************************/
GlRenderTask::GlRenderTask(GlProgram* program, GlRenderTask* other): mProgram(program)
{
@ -33,6 +36,7 @@ GlRenderTask::GlRenderTask(GlProgram* program, GlRenderTask* other): mProgram(pr
mIndexCount = other->mIndexCount;
}
void GlRenderTask::run()
{
// bind shader
@ -45,7 +49,7 @@ void GlRenderTask::run()
}
// setup scissor rect
GL_CHECK(glScissor(mViewport.x, mViewport.y, mViewport.w, mViewport.h));
GL_CHECK(glScissor(mViewport.sx(), mViewport.sy(), mViewport.sw(), mViewport.sh()));
// setup attribute layout
for (uint32_t i = 0; i < mVertexLayout.count; i++) {
@ -81,36 +85,44 @@ void GlRenderTask::run()
}
}
void GlRenderTask::addVertexLayout(const GlVertexLayout &layout)
{
mVertexLayout.push(layout);
}
void GlRenderTask::addBindResource(const GlBindingResource &binding)
{
mBindingResources.push(binding);
}
void GlRenderTask::setDrawRange(uint32_t offset, uint32_t count)
{
mIndexOffset = offset;
mIndexCount = count;
}
void GlRenderTask::setViewport(const RenderRegion &viewport)
{
mViewport = viewport;
if (mViewport.w < 0) {
mViewport.w = 0;
}
if (mViewport.h < 0) {
mViewport.h = 0;
}
if (mViewport.max.x < mViewport.min.x) mViewport.max.x = mViewport.min.x;
if (mViewport.max.y < mViewport.min.y) mViewport.max.y = mViewport.min.y;
}
/************************************************************************/
/* GlStencilCoverTask Class Implementation */
/************************************************************************/
GlStencilCoverTask::GlStencilCoverTask(GlRenderTask* stencil, GlRenderTask* cover, GlStencilMode mode)
:GlRenderTask(nullptr), mStencilTask(stencil), mCoverTask(cover), mStencilMode(mode) {}
:GlRenderTask(nullptr), mStencilTask(stencil), mCoverTask(cover), mStencilMode(mode)
{
}
GlStencilCoverTask::~GlStencilCoverTask()
{
@ -118,6 +130,7 @@ GlStencilCoverTask::~GlStencilCoverTask()
delete mCoverTask;
}
void GlStencilCoverTask::run()
{
GL_CHECK(glEnable(GL_STENCIL_TEST));
@ -151,12 +164,18 @@ void GlStencilCoverTask::run()
GL_CHECK(glDisable(GL_STENCIL_TEST));
}
void GlStencilCoverTask::normalizeDrawDepth(int32_t maxDepth)
{
mCoverTask->normalizeDrawDepth(maxDepth);
mStencilTask->normalizeDrawDepth(maxDepth);
}
/************************************************************************/
/* GlComposeTask Class Implementation */
/************************************************************************/
GlComposeTask::GlComposeTask(GlProgram* program, GLuint target, GlRenderTarget* fbo, Array<GlRenderTask*>&& tasks)
:GlRenderTask(program) ,mTargetFbo(target), mFbo(fbo), mTasks()
{
@ -164,12 +183,14 @@ GlComposeTask::GlComposeTask(GlProgram* program, GLuint target, GlRenderTarget*
tasks.clear();
}
GlComposeTask::~GlComposeTask()
{
ARRAY_FOREACH(p, mTasks) delete(*p);
mTasks.clear();
}
void GlComposeTask::run()
{
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, getSelfFbo()));
@ -209,29 +230,43 @@ void GlComposeTask::run()
onResolve();
}
GLuint GlComposeTask::getSelfFbo() { return mFbo->getFboId(); }
GLuint GlComposeTask::getResolveFboId() { return mFbo->getResolveFboId(); }
GLuint GlComposeTask::getSelfFbo()
{
return mFbo->getFboId();
}
void GlComposeTask::onResolve() {
GLuint GlComposeTask::getResolveFboId()
{
return mFbo->getResolveFboId();
}
void GlComposeTask::onResolve()
{
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, getSelfFbo()));
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, getResolveFboId()));
GL_CHECK(glBlitFramebuffer(0, 0, mRenderWidth, mRenderHeight, 0, 0, mRenderWidth, mRenderHeight, GL_COLOR_BUFFER_BIT, GL_NEAREST));
}
/************************************************************************/
/* GlBlitTask Class Implementation */
/************************************************************************/
GlBlitTask::GlBlitTask(GlProgram* program, GLuint target, GlRenderTarget* fbo, Array<GlRenderTask*>&& tasks)
: GlComposeTask(program, target, fbo, std::move(tasks)), mColorTex(fbo->getColorTexture())
{
}
void GlBlitTask::run()
{
GlComposeTask::run();
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, getTargetFbo()));
GL_CHECK(glViewport(mTargetViewport.x, mTargetViewport.y, mTargetViewport.w, mTargetViewport.h));
GL_CHECK(glViewport(mTargetViewport.x(), mTargetViewport.y(), mTargetViewport.w(), mTargetViewport.h()));
if (mClearBuffer) {
GL_CHECK(glClearColor(0, 0, 0, 0));
@ -246,16 +281,24 @@ void GlBlitTask::run()
GlRenderTask::run();
}
/************************************************************************/
/* GlDrawBlitTask Class Implementation */
/************************************************************************/
GlDrawBlitTask::GlDrawBlitTask(GlProgram* program, GLuint target, GlRenderTarget* fbo, Array<GlRenderTask*>&& tasks)
: GlComposeTask(program, target, fbo, std::move(tasks))
{
}
GlDrawBlitTask::~GlDrawBlitTask()
{
if (mPrevTask) delete mPrevTask;
}
void GlDrawBlitTask::run()
{
if (mPrevTask) mPrevTask->run();
@ -269,15 +312,22 @@ void GlDrawBlitTask::run()
GlRenderTask::run();
}
/************************************************************************/
/* GlClipTask Class Implementation */
/************************************************************************/
GlClipTask::GlClipTask(GlRenderTask* clip, GlRenderTask* mask)
:GlRenderTask(nullptr), mClipTask(clip), mMaskTask(mask) {}
GlClipTask::~GlClipTask()
{
delete mClipTask;
delete mMaskTask;
}
void GlClipTask::run()
{
GL_CHECK(glEnable(GL_STENCIL_TEST));
@ -304,14 +354,22 @@ void GlClipTask::run()
GL_CHECK(glDisable(GL_STENCIL_TEST));
}
void GlClipTask::normalizeDrawDepth(int32_t maxDepth)
{
mClipTask->normalizeDrawDepth(maxDepth);
mMaskTask->normalizeDrawDepth(maxDepth);
}
/************************************************************************/
/* GlSimpleBlendTask Class Implementation */
/************************************************************************/
GlSimpleBlendTask::GlSimpleBlendTask(BlendMethod method, GlProgram* program)
: GlRenderTask(program), mBlendMethod(method) {}
: GlRenderTask(program), mBlendMethod(method)
{
}
void GlSimpleBlendTask::run()
{
@ -332,8 +390,17 @@ void GlSimpleBlendTask::run()
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
/************************************************************************/
/* GlComplexBlendTask Class Implementation */
/************************************************************************/
GlComplexBlendTask::GlComplexBlendTask(GlProgram* program, GlRenderTarget* dstFbo, GlRenderTarget* dstCopyFbo, GlRenderTask* stencilTask, GlComposeTask* composeTask)
: GlRenderTask(program), mDstFbo(dstFbo), mDstCopyFbo(dstCopyFbo), mStencilTask(stencilTask), mComposeTask(composeTask) {}
: GlRenderTask(program), mDstFbo(dstFbo), mDstCopyFbo(dstCopyFbo), mStencilTask(stencilTask), mComposeTask(composeTask)
{
}
GlComplexBlendTask::~GlComplexBlendTask()
{
@ -341,6 +408,7 @@ GlComplexBlendTask::~GlComplexBlendTask()
delete mComposeTask;
}
void GlComplexBlendTask::run()
{
mComposeTask->run();
@ -349,12 +417,11 @@ void GlComplexBlendTask::run()
GL_CHECK(glBindFramebuffer(GL_READ_FRAMEBUFFER, mDstFbo->getFboId()));
GL_CHECK(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mDstCopyFbo->getResolveFboId()));
GL_CHECK(glViewport(0, 0, mDstFbo->getViewport().w, mDstFbo->getViewport().h));
GL_CHECK(glScissor(0, 0, mDstFbo->getViewport().w, mDstFbo->getViewport().h));
GL_CHECK(glViewport(0, 0, mDstFbo->getViewport().w(), mDstFbo->getViewport().h()));
GL_CHECK(glScissor(0, 0, mDstFbo->getViewport().w(), mDstFbo->getViewport().h()));
const auto& vp = getViewport();
GL_CHECK(glBlitFramebuffer(vp.x, vp.y, vp.x + vp.w, vp.y + vp.h, 0, 0, vp.w, vp.h, GL_COLOR_BUFFER_BIT, GL_LINEAR));
GL_CHECK(glBlitFramebuffer(vp.min.x, vp.min.y, vp.max.x, vp.max.y, 0, 0, vp.w(), vp.h(), GL_COLOR_BUFFER_BIT, GL_LINEAR));
GL_CHECK(glBindFramebuffer(GL_FRAMEBUFFER, mDstFbo->getFboId()));
@ -381,12 +448,17 @@ void GlComplexBlendTask::run()
GL_CHECK(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
}
void GlComplexBlendTask::normalizeDrawDepth(int32_t maxDepth)
{
mStencilTask->normalizeDrawDepth(maxDepth);
GlRenderTask::normalizeDrawDepth(maxDepth);
}
/************************************************************************/
/* GlGaussianBlurTask Class Implementation */
/************************************************************************/
void GlGaussianBlurTask::run()
{
const auto vp = getViewport();
@ -439,6 +511,9 @@ void GlGaussianBlurTask::run()
GL_CHECK(glEnable(GL_BLEND));
}
/************************************************************************/
/* GlEffectDropShadowTask Class Implementation */
/************************************************************************/
void GlEffectDropShadowTask::run()
{
@ -492,6 +567,9 @@ void GlEffectDropShadowTask::run()
GL_CHECK(glEnable(GL_BLEND));
}
/************************************************************************/
/* GlEffectColorTransformTask Class Implementation */
/************************************************************************/
void GlEffectColorTransformTask::run()
{

View file

@ -130,12 +130,10 @@ public:
protected:
GLuint getTargetFbo() { return mTargetFbo; }
GLuint getSelfFbo();
GLuint getResolveFboId();
void onResolve();
private:
GLuint mTargetFbo;
GlRenderTarget* mFbo;

View file

@ -183,10 +183,10 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const RenderColor& c, RenderUpdat
bbox.intersect(vp);
}
auto x = bbox.x - vp.x;
auto y = bbox.y - vp.y;
auto w = bbox.w;
auto h = bbox.h;
auto x = bbox.sx() - vp.sx();
auto y = bbox.sy() - vp.sy();
auto w = bbox.sw();
auto h = bbox.sh();
GlRenderTask* task = nullptr;
if (mBlendMethod != BlendMethod::Normal && !complexBlend) task = new GlSimpleBlendTask(mBlendMethod, mPrograms[RT_Color]);
@ -199,7 +199,8 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const RenderColor& c, RenderUpdat
return;
}
task->setViewport({x, vp.h - y - h, w, h});
y = vp.sh() - y - h;
task->setViewport({{x, y}, {x + w, y + h}});
GlRenderTask* stencilTask = nullptr;
@ -268,7 +269,6 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
{
auto vp = currentPass()->getViewport();
auto bbox = sdata.geometry.viewport;
bbox.intersect(vp);
const Fill::ColorStop* stops = nullptr;
@ -277,13 +277,9 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
GlRenderTask* task = nullptr;
if (fill->type() == Type::LinearGradient) {
task = new GlRenderTask(mPrograms[RT_LinGradient]);
} else if (fill->type() == Type::RadialGradient) {
task = new GlRenderTask(mPrograms[RT_RadGradient]);
} else {
return;
}
if (fill->type() == Type::LinearGradient) task = new GlRenderTask(mPrograms[RT_LinGradient]);
else if (fill->type() == Type::RadialGradient) task = new GlRenderTask(mPrograms[RT_RadGradient]);
else return;
task->setDrawDepth(depth);
@ -293,13 +289,11 @@ void GlRenderer::drawPrimitive(GlShape& sdata, const Fill* fill, RenderUpdateFla
}
auto complexBlend = beginComplexBlending(bbox, sdata.geometry.getBounds());
if (complexBlend) vp = currentPass()->getViewport();
auto x = bbox.x - vp.x;
auto y = bbox.y - vp.y;
task->setViewport({x, vp.h - y - bbox.h, bbox.w, bbox.h});
auto x = bbox.sx() - vp.sx();
auto y = vp.sh() - (bbox.sy() - vp.sy()) - bbox.sh();
task->setViewport({{x, y}, {x + bbox.sw(), y + bbox.sh()}});
GlRenderTask* stencilTask = nullptr;
GlStencilMode stencilMode = sdata.geometry.getStencilMode(flag);
@ -498,22 +492,18 @@ void GlRenderer::drawClip(Array<RenderData>& clips)
for (uint32_t i = 0; i < clips.count; ++i) {
auto sdata = static_cast<GlShape*>(clips[i]);
auto clipTask = new GlRenderTask(mPrograms[RT_Stencil]);
clipTask->setDrawDepth(clipDepths[i]);
auto flag = (sdata->geometry.stroke.vertex.count > 0) ? RenderUpdateFlag::Stroke : RenderUpdateFlag::Path;
sdata->geometry.draw(clipTask, &mGpuBuffer, flag);
auto bbox = sdata->geometry.viewport;
bbox.intersect(vp);
auto x = bbox.x - vp.x;
auto y = bbox.y - vp.y;
clipTask->setViewport({x, vp.h - y - bbox.h, bbox.w, bbox.h});
auto x = bbox.sx() - vp.sx();
auto y = vp.sh() - (bbox.sy() - vp.sy()) - bbox.sh();
clipTask->setViewport({{x, y}, {x + bbox.sw(), y + bbox.sh()}});
float matrix44[16];
currentPass()->getMatrix(matrix44, sdata->geometry.matrix);
@ -529,7 +519,7 @@ void GlRenderer::drawClip(Array<RenderData>& clips)
maskTask->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), identityVertexOffset});
maskTask->addBindResource(GlBindingResource{0, loc, mGpuBuffer.getBufferId(), mat4Offset, 16 * sizeof(float), });
maskTask->setDrawRange(identityIndexOffset, 6);
maskTask->setViewport({0, 0, static_cast<int32_t>(vp.w), static_cast<int32_t>(vp.h)});
maskTask->setViewport({{0, 0}, {vp.sw(), vp.sh()}});
currentPass()->addRenderTask(new GlClipTask(clipTask, maskTask));
}
@ -543,11 +533,10 @@ GlRenderPass* GlRenderer::currentPass()
bool GlRenderer::beginComplexBlending(const RenderRegion& vp, RenderRegion bounds)
{
if (vp.w == 0 || vp.h == 0) return false;
if (vp.invalid()) return false;
bounds.intersect(vp);
if (bounds.w == 0 || bounds.h == 0) return false;
if (bounds.invalid()) return false;
if (mBlendMethod == BlendMethod::Normal || mBlendMethod == BlendMethod::Add || mBlendMethod == BlendMethod::Darken || mBlendMethod == BlendMethod::Lighten) return false;
@ -573,37 +562,26 @@ void GlRenderer::endBlendingCompose(GlRenderTask* stencilTask, const Matrix& mat
if (mBlendPool.count < 2) mBlendPool.push(new GlRenderTargetPool(surface.w, surface.h));
auto dstCopyFbo = mBlendPool[1]->getRenderTarget(vp);
{
const auto& passVp = currentPass()->getViewport();
auto x = vp.x;
auto y = vp.y;
auto w = vp.w;
auto h = vp.h;
stencilTask->setViewport({x, passVp.h - y - h, w, h});
}
auto x = vp.sx();
auto y = currentPass()->getViewport().sh() - vp.sy() - vp.sh();
stencilTask->setViewport({{x, y}, {x + vp.sw(), y + vp.sh()}});
stencilTask->setDrawDepth(currentPass()->nextDrawDepth());
{
// set view matrix
float matrix44[16];
currentPass()->getMatrix(matrix44, matrix);
uint32_t viewOffset = mGpuBuffer.push(matrix44, 16 * sizeof(float), true);
stencilTask->addBindResource(GlBindingResource{
0,
stencilTask->getProgram()->getUniformBlockIndex("Matrix"),
mGpuBuffer.getBufferId(),
viewOffset,
16 * sizeof(float),
});
}
// set view matrix
float matrix44[16];
currentPass()->getMatrix(matrix44, matrix);
uint32_t viewOffset = mGpuBuffer.push(matrix44, 16 * sizeof(float), true);
stencilTask->addBindResource(GlBindingResource{
0,
stencilTask->getProgram()->getUniformBlockIndex("Matrix"),
mGpuBuffer.getBufferId(),
viewOffset,
16 * sizeof(float),
});
auto task = new GlComplexBlendTask(getBlendProgram(), currentPass()->getFbo(), dstCopyFbo, stencilTask, composeTask);
prepareCmpTask(task, vp, blendPass->getFboWidth(), blendPass->getFboHeight());
task->setDrawDepth(currentPass()->nextDrawDepth());
// src and dst texture
@ -634,8 +612,7 @@ GlProgram* GlRenderer::getBlendProgram()
void GlRenderer::prepareBlitTask(GlBlitTask* task)
{
RenderRegion region{0, 0, static_cast<int32_t>(surface.w), static_cast<int32_t>(surface.h)};
prepareCmpTask(task, region, surface.w, surface.h);
prepareCmpTask(task, {{0, 0}, {int32_t(surface.w), int32_t(surface.h)}}, surface.w, surface.h);
task->addBindResource(GlBindingResource{0, task->getColorTexture(), task->getProgram()->getUniformLocation("uSrcTexture")});
}
@ -650,13 +627,13 @@ void GlRenderer::prepareCmpTask(GlRenderTask* task, const RenderRegion& vp, uint
auto taskVp = vp;
taskVp.intersect(passVp);
auto x = taskVp.x - passVp.x;
auto y = taskVp.y - passVp.y;
auto w = taskVp.w;
auto h = taskVp.h;
auto x = taskVp.sx() - passVp.sx();
auto y = taskVp.sy() - passVp.sy();
auto w = taskVp.sw();
auto h = taskVp.sh();
float rw = static_cast<float>(passVp.w);
float rh = static_cast<float>(passVp.h);
float rw = static_cast<float>(passVp.w());
float rh = static_cast<float>(passVp.h());
float l = static_cast<float>(x);
float t = static_cast<float>(rh - y);
@ -707,10 +684,9 @@ void GlRenderer::prepareCmpTask(GlRenderTask* task, const RenderRegion& vp, uint
task->addVertexLayout(GlVertexLayout{0, 2, 4 * sizeof(float), vertexOffset});
task->addVertexLayout(GlVertexLayout{1, 2, 4 * sizeof(float), vertexOffset + 2 * sizeof(float)});
task->setDrawRange(indexOffset, indices.count);
task->setViewport({x, static_cast<int32_t>((passVp.h - y - h)), w, h});
y = (passVp.sh() - y - h);
task->setViewport({{x, y}, {x + w, y + h}});
}
@ -743,11 +719,11 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp)
if (program && !selfPass->isEmpty() && !maskPass->isEmpty()) {
auto prev_task = maskPass->endRenderPass<GlComposeTask>(nullptr, currentPass()->getFboId());
prev_task->setDrawDepth(currentPass()->nextDrawDepth());
prev_task->setRenderSize(static_cast<uint32_t>(glCmp->bbox.w), static_cast<uint32_t>(glCmp->bbox.h));
prev_task->setRenderSize(glCmp->bbox.w(), glCmp->bbox.h());
prev_task->setViewport(glCmp->bbox);
auto compose_task = selfPass->endRenderPass<GlDrawBlitTask>(program, currentPass()->getFboId());
compose_task->setRenderSize(static_cast<uint32_t>(glCmp->bbox.w), static_cast<uint32_t>(glCmp->bbox.h));
compose_task->setRenderSize(glCmp->bbox.w(), glCmp->bbox.h());
compose_task->setPrevTask(prev_task);
prepareCmpTask(compose_task, glCmp->bbox, selfPass->getFboWidth(), selfPass->getFboHeight());
@ -756,7 +732,7 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp)
compose_task->addBindResource(GlBindingResource{1, maskPass->getTextureId(), program->getUniformLocation("uMaskTexture")});
compose_task->setDrawDepth(currentPass()->nextDrawDepth());
compose_task->setParentSize(static_cast<uint32_t>(currentPass()->getViewport().w), static_cast<uint32_t>(currentPass()->getViewport().h));
compose_task->setParentSize(currentPass()->getViewport().w(), currentPass()->getViewport().h());
currentPass()->addRenderTask(compose_task);
}
@ -769,7 +745,7 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp)
if (!renderPass->isEmpty()) {
auto task = renderPass->endRenderPass<GlDrawBlitTask>(mPrograms[RT_Image], currentPass()->getFboId());
task->setRenderSize(static_cast<uint32_t>(glCmp->bbox.w), static_cast<uint32_t>(glCmp->bbox.h));
task->setRenderSize(glCmp->bbox.w(), glCmp->bbox.h());
prepareCmpTask(task, glCmp->bbox, renderPass->getFboWidth(), renderPass->getFboHeight());
task->setDrawDepth(currentPass()->nextDrawDepth());
@ -797,7 +773,7 @@ void GlRenderer::endRenderPass(RenderCompositor* cmp)
// texture id
task->addBindResource(GlBindingResource{0, renderPass->getTextureId(), task->getProgram()->getUniformLocation("uTexture")});
task->setParentSize(static_cast<uint32_t>(currentPass()->getViewport().w), static_cast<uint32_t>(currentPass()->getViewport().h));
task->setParentSize(currentPass()->getViewport().w(), currentPass()->getViewport().h());
currentPass()->addRenderTask(std::move(task));
}
delete(renderPass);
@ -836,7 +812,7 @@ bool GlRenderer::target(void* context, int32_t id, uint32_t w, uint32_t h)
currentContext();
mRootTarget.setViewport({0, 0, static_cast<int32_t>(surface.w), static_cast<int32_t>(surface.h)});
mRootTarget.setViewport({{0, 0}, {int32_t(surface.w), int32_t(surface.h)}});
mRootTarget.init(surface.w, surface.h, mTargetFboId);
return true;
@ -864,7 +840,7 @@ bool GlRenderer::sync()
prepareBlitTask(task);
task->mClearBuffer = mClearBuffer;
task->setTargetViewport({0, 0, static_cast<int32_t>(surface.w), static_cast<int32_t>(surface.h)});
task->setTargetViewport({{0, 0}, {int32_t(surface.w), int32_t(surface.h)}});
if (mGpuBuffer.flushToGPU()) {
mGpuBuffer.bind();
@ -935,20 +911,11 @@ bool GlRenderer::beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_
cmp->opacity = opacity;
uint32_t index = mRenderPassStack.count - 1;
if (index >= mComposePool.count) {
mComposePool.push( new GlRenderTargetPool(surface.w, surface.h));
}
if (index >= mComposePool.count) mComposePool.push( new GlRenderTargetPool(surface.w, surface.h));
auto glCmp = static_cast<GlCompositor*>(cmp);
if (glCmp->bbox.w > 0 && glCmp->bbox.h > 0) {
auto renderTarget = mComposePool[index]->getRenderTarget(glCmp->bbox);
mRenderPassStack.push(new GlRenderPass(renderTarget));
} else {
// empty render pass
mRenderPassStack.push(new GlRenderPass(nullptr));
}
if (glCmp->bbox.valid()) mRenderPassStack.push(new GlRenderPass(mComposePool[index]->getRenderTarget(glCmp->bbox)));
else mRenderPassStack.push(new GlRenderPass(nullptr));
return true;
}
@ -1069,12 +1036,12 @@ bool GlRenderer::effectGaussianBlurRegion(RenderEffectGaussianBlur* effect)
{
auto gaussianBlur = (GlGaussianBlur*)effect->rd;
if (effect->direction != 2) {
effect->extend.x = -gaussianBlur->extend;
effect->extend.w = +gaussianBlur->extend * 2;
effect->extend.min.x = -gaussianBlur->extend;
effect->extend.max.x = +gaussianBlur->extend;
}
if (effect->direction != 1) {
effect->extend.y = -gaussianBlur->extend;
effect->extend.h = +gaussianBlur->extend * 2;
effect->extend.min.y = -gaussianBlur->extend;
effect->extend.max.y = +gaussianBlur->extend;
}
return true;
};
@ -1083,10 +1050,10 @@ bool GlRenderer::effectGaussianBlurRegion(RenderEffectGaussianBlur* effect)
bool GlRenderer::effectDropShadowRegion(RenderEffectDropShadow* effect)
{
auto gaussianBlur = (GlDropShadow*)effect->rd;
effect->extend.x = -gaussianBlur->extend;
effect->extend.w = +gaussianBlur->extend * 2;
effect->extend.y = -gaussianBlur->extend;
effect->extend.h = +gaussianBlur->extend * 2;
effect->extend.min.x = -gaussianBlur->extend;
effect->extend.max.x = +gaussianBlur->extend;
effect->extend.min.y = -gaussianBlur->extend;
effect->extend.max.y = +gaussianBlur->extend;
return true;
};
@ -1136,7 +1103,6 @@ bool GlRenderer::render(TVG_UNUSED RenderCompositor* cmp, const RenderEffect* ef
auto voffset = mGpuBuffer.push((void*)vdata, sizeof(vdata));
auto ioffset = mGpuBuffer.pushIndex((void*)idata, sizeof(idata));
// effect gaussian blur
if (effect->type == SceneEffect::GaussianBlur) {
// get gaussian programs
GlProgram* programHorz = mPrograms[RT_GaussianHorz];
@ -1152,7 +1118,7 @@ bool GlRenderer::render(TVG_UNUSED RenderCompositor* cmp, const RenderEffect* ef
// create gaussian blur tasks
auto gaussianTask = new GlGaussianBlurTask(dstFbo, dstCopyFbo0, dstCopyFbo1);
gaussianTask->effect = (RenderEffectGaussianBlur*)effect;
gaussianTask->setViewport({0, 0, vp.w, vp.h});
gaussianTask->setViewport({{0, 0}, {vp.sw(), vp.sh()}});
// horizontal blur task and geometry
gaussianTask->horzTask = new GlRenderTask(programHorz);
gaussianTask->horzTask->addBindResource(GlBindingResource{0, programHorz->getUniformBlockIndex("Gaussian"), mGpuBuffer.getBufferId(), blurOffset, sizeof(GlGaussianBlur)});
@ -1165,8 +1131,7 @@ bool GlRenderer::render(TVG_UNUSED RenderCompositor* cmp, const RenderEffect* ef
gaussianTask->vertTask->setDrawRange(ioffset, 6);
// add task to render pipeline
pass->addRenderTask(gaussianTask);
} // effect drop shadow
else if (effect->type == SceneEffect::DropShadow) {
} else if (effect->type == SceneEffect::DropShadow) {
// get programs
GlProgram* program = mPrograms[RT_DropShadow];
GlProgram* programHorz = mPrograms[RT_GaussianHorz];
@ -1182,7 +1147,7 @@ bool GlRenderer::render(TVG_UNUSED RenderCompositor* cmp, const RenderEffect* ef
// create gaussian blur tasks
auto task = new GlEffectDropShadowTask(program, dstFbo, dstCopyFbo0, dstCopyFbo1);
task->effect = (RenderEffectDropShadow*)effect;
task->setViewport({0, 0, vp.w, vp.h});
task->setViewport({{0, 0}, {vp.sw(), vp.sh()}});
task->addBindResource(GlBindingResource{0, program->getUniformBlockIndex("DropShadow"), mGpuBuffer.getBufferId(), paramsOffset, sizeof(GlDropShadow)});
task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset});
task->setDrawRange(ioffset, 6);
@ -1198,8 +1163,7 @@ bool GlRenderer::render(TVG_UNUSED RenderCompositor* cmp, const RenderEffect* ef
task->vertTask->setDrawRange(ioffset, 6);
// add task to render pipeline
pass->addRenderTask(task);
} // effect fill, tint, tritone
else if ((effect->type == SceneEffect::Fill) || (effect->type == SceneEffect::Tint) || (effect->type == SceneEffect::Tritone)) {
} else if ((effect->type == SceneEffect::Fill) || (effect->type == SceneEffect::Tint) || (effect->type == SceneEffect::Tritone)) {
GlProgram* program{};
if (effect->type == SceneEffect::Fill) program = mPrograms[RT_EffectFill];
else if (effect->type == SceneEffect::Tint) program = mPrograms[RT_EffectTint];
@ -1213,7 +1177,7 @@ bool GlRenderer::render(TVG_UNUSED RenderCompositor* cmp, const RenderEffect* ef
auto paramsOffset = mGpuBuffer.push(params, sizeof(GlEffectParams), true);
// create and setup task
auto task = new GlEffectColorTransformTask(program, dstFbo, dstCopyFbo);
task->setViewport({0, 0, vp.w, vp.h});
task->setViewport({{0, 0}, {vp.sw(), vp.sh()}});
task->addBindResource(GlBindingResource{0, program->getUniformBlockIndex("Params"), mGpuBuffer.getBufferId(), paramsOffset, sizeof(GlEffectParams)});
task->addVertexLayout(GlVertexLayout{0, 2, 2 * sizeof(float), voffset});
task->setDrawRange(ioffset, 6);
@ -1256,25 +1220,18 @@ bool GlRenderer::blend(BlendMethod method)
bool GlRenderer::renderImage(void* data)
{
auto sdata = static_cast<GlShape*>(data);
if (!sdata) return false;
if (currentPass()->isEmpty()) return true;
if (currentPass()->isEmpty() || !(sdata->updateFlag & RenderUpdateFlag::Image)) return true;
if ((sdata->updateFlag & RenderUpdateFlag::Image) == 0) return true;
auto vp = currentPass()->getViewport();
auto bbox = sdata->geometry.viewport;
bbox.intersect(vp);
if (bbox.invalid()) return true;
if (bbox.w <= 0 || bbox.h <= 0) return true;
auto x = bbox.x - vp.x;
auto y = bbox.y - vp.y;
int32_t drawDepth = currentPass()->nextDrawDepth();
auto x = bbox.sx() - vp.sx();
auto y = bbox.sy() - vp.sy();
auto drawDepth = currentPass()->nextDrawDepth();
if (!sdata->clips.empty()) drawClip(sdata->clips);
@ -1287,7 +1244,6 @@ bool GlRenderer::renderImage(void* data)
}
bool complexBlend = beginComplexBlending(bbox, sdata->geometry.getBounds());
if (complexBlend) vp = currentPass()->getViewport();
// matrix buffer
@ -1316,7 +1272,11 @@ bool GlRenderer::renderImage(void* data)
// texture id
task->addBindResource(GlBindingResource{0, sdata->texId, task->getProgram()->getUniformLocation("uTexture")});
task->setViewport({x, vp.h - y - bbox.h, bbox.w, bbox.h});
y = vp.sh() - y - bbox.sh();
auto x2 = x + bbox.sw();
auto y2 = y + bbox.sh();
task->setViewport({{x, y}, {x2, y2}});
currentPass()->addRenderTask(task);
@ -1332,33 +1292,25 @@ bool GlRenderer::renderImage(void* data)
bool GlRenderer::renderShape(RenderData data)
{
auto sdata = static_cast<GlShape*>(data);
if (currentPass()->isEmpty()) return true;
auto sdata = static_cast<GlShape*>(data);
if (sdata->updateFlag == RenderUpdateFlag::None) return true;
const auto& vp = currentPass()->getViewport();
auto bbox = sdata->geometry.viewport;
bbox.intersect(vp);
if (bbox.w <= 0 || bbox.h <= 0) return true;
bbox.intersect(currentPass()->getViewport());
if (bbox.invalid()) return true;
int32_t drawDepth1 = 0, drawDepth2 = 0;
size_t flags = static_cast<size_t>(sdata->updateFlag);
if (flags == 0) return false;
if (flags & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Color)) drawDepth1 = currentPass()->nextDrawDepth();
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::GradientStroke)) drawDepth2 = currentPass()->nextDrawDepth();
if (sdata->updateFlag == RenderUpdateFlag::None) return false;
if (sdata->updateFlag & (RenderUpdateFlag::Gradient | RenderUpdateFlag::Color)) drawDepth1 = currentPass()->nextDrawDepth();
if (sdata->updateFlag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::GradientStroke)) drawDepth2 = currentPass()->nextDrawDepth();
if (!sdata->clips.empty()) drawClip(sdata->clips);
auto processFill = [&]() {
if (flags & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient)) {
if (sdata->updateFlag & (RenderUpdateFlag::Color | RenderUpdateFlag::Gradient)) {
if (const auto& gradient = sdata->rshape->fill) {
drawPrimitive(*sdata, gradient, RenderUpdateFlag::Gradient, drawDepth1);
} else if (sdata->rshape->color.a > 0) {
@ -1369,7 +1321,7 @@ bool GlRenderer::renderShape(RenderData data)
auto processStroke = [&]() {
if (!sdata->rshape->stroke) return;
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::GradientStroke)) {
if (sdata->updateFlag & (RenderUpdateFlag::Stroke | RenderUpdateFlag::GradientStroke)) {
if (const auto& gradient = sdata->rshape->strokeFill()) {
drawPrimitive(*sdata, gradient, RenderUpdateFlag::GradientStroke, drawDepth2);
} else if (sdata->rshape->stroke->color.a > 0) {

View file

@ -1516,12 +1516,7 @@ void Stroker::stroke(const RenderShape *rshape, const RenderPath& path)
RenderRegion Stroker::bounds() const
{
return RenderRegion {
static_cast<int32_t>(floor(mLeftTop.x)),
static_cast<int32_t>(floor(mLeftTop.y)),
static_cast<int32_t>(ceil(mRightBottom.x - floor(mLeftTop.x))),
static_cast<int32_t>(ceil(mRightBottom.y - floor(mLeftTop.y))),
};
return {{int32_t(floor(mLeftTop.x)), int32_t(floor(mLeftTop.y))}, {int32_t(ceil(mRightBottom.x)), int32_t(ceil(mRightBottom.y))}};
}
@ -2197,26 +2192,15 @@ void BWTessellator::tessellate(const RenderPath& path, const Matrix& matrix)
RenderRegion BWTessellator::bounds() const
{
return RenderRegion {
static_cast<int32_t>(floor(bbox.min.x)),
static_cast<int32_t>(floor(bbox.min.y)),
static_cast<int32_t>(ceil(bbox.max.x - floor(bbox.min.x))),
static_cast<int32_t>(ceil(bbox.max.y - floor(bbox.min.y))),
};
return {{int32_t(floor(bbox.min.x)), int32_t(floor(bbox.min.y))}, {int32_t(ceil(bbox.max.x)), int32_t(ceil(bbox.max.y))}};
}
uint32_t BWTessellator::pushVertex(float x, float y)
{
auto index = _pushVertex(mBuffer->vertex, x, y);
if (index == 0) {
bbox.max = bbox.min = {x, y};
} else {
bbox.min = {std::min(bbox.min.x, x), std::min(bbox.min.y, y)};
bbox.max = {std::max(bbox.max.x, x), std::max(bbox.max.y, y)};
}
if (index == 0) bbox.max = bbox.min = {x, y};
else bbox = {{std::min(bbox.min.x, x), std::min(bbox.min.y, y)}, {std::max(bbox.max.x, x), std::max(bbox.max.y, y)}};
return index;
}

View file

@ -156,7 +156,7 @@ private:
void pushTriangle(uint32_t a, uint32_t b, uint32_t c);
GlGeometryBuffer* mBuffer;
BBox bbox = {{}, {}};
BBox bbox = {};
};
} // namespace tvg

View file

@ -141,12 +141,12 @@ bool effectGaussianBlurRegion(RenderEffectGaussianBlur* params)
auto extra = static_cast<SwGaussianBlur*>(params->rd)->extends;
if (params->direction != 2) {
region.x = -extra;
region.w = extra * 2;
region.min.x = -extra;
region.max.x = extra;
}
if (params->direction != 1) {
region.y = -extra;
region.h = extra * 2;
region.min.y = -extra;
region.max.y = extra;
}
return true;
@ -299,15 +299,14 @@ bool effectDropShadowRegion(RenderEffectDropShadow* params)
auto& offset = static_cast<SwDropShadow*>(params->rd)->offset;
auto extra = static_cast<SwDropShadow*>(params->rd)->extends;
region.x = -extra;
region.w = extra * 2;
region.y = -extra;
region.h = extra * 2;
region.min = {-extra, -extra};
region.max = {extra, extra};
region.x = std::min(region.x + (int32_t)offset.x, region.x);
region.y = std::min(region.y + (int32_t)offset.y, region.y);
region.w += abs(offset.x);
region.h += abs(offset.y);
if (offset.x < 0) region.min.x += (int32_t) offset.x;
else region.max.x += offset.x;
if (offset.y < 0) region.min.y += (int32_t) offset.y;
else region.max.y += offset.y;
return true;
}

View file

@ -54,14 +54,10 @@ struct SwTask : Task
done();
RenderRegion region;
//Range over?
region.x = bbox.min.x > 0 ? bbox.min.x : 0;
region.y = bbox.min.y > 0 ? bbox.min.y : 0;
region.w = bbox.max.x - region.x;
region.h = bbox.max.y - region.y;
if (region.w < 0) region.w = 0;
if (region.h < 0) region.h = 0;
region.min.x = bbox.min.x > 0 ? bbox.min.x : 0;
region.min.y = bbox.min.y > 0 ? bbox.min.y : 0;
region.max.x = bbox.max.x > bbox.min.x ? bbox.max.x : bbox.min.x;
region.max.y = bbox.max.y > bbox.min.y ? bbox.max.y : bbox.min.y;
return region;
}
@ -570,38 +566,40 @@ SwSurface* SwRenderer::request(int channelSize, bool square)
RenderCompositor* SwRenderer::target(const RenderRegion& region, ColorSpace cs, CompositionFlag flags)
{
auto x = region.x;
auto y = region.y;
auto w = region.w;
auto h = region.h;
auto min = region.min;
auto max = region.max;
auto sw = static_cast<int32_t>(surface->w);
auto sh = static_cast<int32_t>(surface->h);
//Out of boundary
if (x >= sw || y >= sh || x + w < 0 || y + h < 0) return nullptr;
if (min.x >= sw || min.y >= sh || max.x < 0 || max.y < 0) return nullptr;
auto cmp = request(CHANNEL_SIZE(cs), (flags & CompositionFlag::PostProcessing));
//Boundary Check
if (x < 0) x = 0;
if (y < 0) y = 0;
if (x + w > sw) w = (sw - x);
if (y + h > sh) h = (sh - y);
if (min.x < 0) min.x = 0;
if (min.y < 0) min.y = 0;
if (max.x > sw) max.x = (sw - min.x);
if (max.y > sh) max.y = (sh - min.y);
auto w = max.x - min.x;
auto h = max.y - min.y;
if (w == 0 || h == 0) return nullptr;
cmp->compositor->recoverSfc = surface;
cmp->compositor->recoverCmp = surface->compositor;
cmp->compositor->valid = false;
cmp->compositor->bbox.min.x = x;
cmp->compositor->bbox.min.y = y;
cmp->compositor->bbox.max.x = x + w;
cmp->compositor->bbox.max.y = y + h;
cmp->compositor->bbox.min.x = min.x;
cmp->compositor->bbox.min.y = min.y;
cmp->compositor->bbox.max.x = max.x;
cmp->compositor->bbox.max.y = max.y;
/* TODO: Currently, only blending might work.
Blending and composition must be handled together. */
auto color = (surface->blender && !surface->compositor) ? 0x00ffffff : 0x00000000;
rasterClear(cmp, x, y, w, h, color);
rasterClear(cmp, min.x, min.y, w, h, color);
//Switch render target
surface = cmp;
@ -737,10 +735,10 @@ void* SwRenderer::prepareCommon(SwTask* task, const Matrix& transform, const Arr
task->surface = surface;
task->mpool = mpool;
task->flags = flags;
task->bbox.min.x = std::max(static_cast<SwCoord>(0), static_cast<SwCoord>(vport.x));
task->bbox.min.y = std::max(static_cast<SwCoord>(0), static_cast<SwCoord>(vport.y));
task->bbox.max.x = std::min(static_cast<SwCoord>(surface->w), static_cast<SwCoord>(vport.x + vport.w));
task->bbox.max.y = std::min(static_cast<SwCoord>(surface->h), static_cast<SwCoord>(vport.y + vport.h));
task->bbox.min.x = std::max(static_cast<SwCoord>(0), static_cast<SwCoord>(vport.min.x));
task->bbox.min.y = std::max(static_cast<SwCoord>(0), static_cast<SwCoord>(vport.min.y));
task->bbox.max.x = std::min(static_cast<SwCoord>(surface->w), static_cast<SwCoord>(vport.max.x));
task->bbox.max.y = std::min(static_cast<SwCoord>(surface->h), static_cast<SwCoord>(vport.max.y));
if (!task->pushed) {
task->pushed = true;

View file

@ -31,7 +31,7 @@ struct Canvas::Impl
{
Scene* scene;
RenderMethod* renderer;
RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX};
RenderRegion vport = {{0, 0}, {INT32_MAX, INT32_MAX}};
Status status = Status::Synced;
Impl() : scene(Scene::gen())
@ -119,11 +119,11 @@ struct Canvas::Impl
{
if (status != Status::Damaged && status != Status::Synced) return Result::InsufficientCondition;
RenderRegion val = {x, y, w, h};
RenderRegion val = {{x, y}, {x + w, y + h}};
//intersect if the target buffer is already set.
auto surface = renderer->mainSurface();
if (surface && surface->w > 0 && surface->h > 0) {
val.intersect({0, 0, (int32_t)surface->w, (int32_t)surface->h});
val.intersect({{0, 0}, {(int32_t)surface->w, (int32_t)surface->h}});
}
if (vport == val) return Result::Success;
renderer->viewport(val);

View file

@ -51,7 +51,7 @@ Result GlCanvas::target(void* context, int32_t id, uint32_t w, uint32_t h, Color
if (!renderer) return Result::MemoryCorruption;
if (!renderer->target(context, id, w, h)) return Result::Unknown;
pImpl->vport = {0, 0, (int32_t)w, (int32_t)h};
pImpl->vport = {{0, 0}, {(int32_t)w, (int32_t)h}};
renderer->viewport(pImpl->vport);
//Paints must be updated again with this new target.

View file

@ -58,7 +58,7 @@ static Result _clipRect(RenderMethod* renderer, const Point* pts, const Matrix&
if (tmp[i].y > max.y) max.y = tmp[i].y;
}
float region[4] = {float(before.x), float(before.x + before.w), float(before.y), float(before.y + before.h)};
float region[4] = {float(before.min.x), float(before.max.x), float(before.min.y), float(before.max.y)};
//figure out if the clipper is a superset of the current viewport(before) region
if (min.x <= region[0] && max.x >= region[1] && min.y <= region[2] && max.y >= region[3]) {
@ -66,7 +66,7 @@ static Result _clipRect(RenderMethod* renderer, const Point* pts, const Matrix&
return Result::Success;
//figure out if the clipper is totally outside of the viewport
} else if (max.x <= region[0] || min.x >= region[1] || max.y <= region[2] || min.y >= region[3]) {
renderer->viewport({0, 0, 0, 0});
renderer->viewport({});
return Result::Success;
}
return Result::InsufficientCondition;
@ -122,13 +122,13 @@ static Result _compFastTrack(RenderMethod* renderer, Paint* cmpTarget, const Mat
if (v1.x > v2.x) std::swap(v1.x, v2.x);
if (v1.y > v2.y) std::swap(v1.y, v2.y);
after.x = static_cast<int32_t>(nearbyint(v1.x));
after.y = static_cast<int32_t>(nearbyint(v1.y));
after.w = static_cast<int32_t>(nearbyint(v2.x)) - after.x;
after.h = static_cast<int32_t>(nearbyint(v2.y)) - after.y;
after.min.x = static_cast<int32_t>(nearbyint(v1.x));
after.min.y = static_cast<int32_t>(nearbyint(v1.y));
after.max.x = static_cast<int32_t>(nearbyint(v2.x));
after.max.y = static_cast<int32_t>(nearbyint(v2.y));
if (after.w < 0) after.w = 0;
if (after.h < 0) after.h = 0;
if (after.max.x < after.min.x) after.max.x = after.min.x;
if (after.max.y < after.min.y) after.max.y = after.min.y;
after.intersect(before);
renderer->viewport(after);
@ -185,7 +185,7 @@ bool Paint::Impl::render(RenderMethod* renderer)
PAINT_METHOD(region, bounds(renderer));
if (MASK_REGION_MERGING(maskData->method)) region.add(PAINT(maskData->target)->bounds(renderer));
if (region.w == 0 || region.h == 0) return true;
if (region.invalid()) return true;
cmp = renderer->target(region, MASK_TO_COLORSPACE(renderer, maskData->method), CompositionFlag::Masking);
if (renderer->beginComposite(cmp, MaskMethod::None, 255)) {
maskData->target->pImpl->render(renderer);

View file

@ -273,7 +273,7 @@ struct PictureImpl : Picture
{
if (impl.rd) return renderer->region(impl.rd);
if (vector) return vector->pImpl->bounds(renderer);
return {0, 0, 0, 0};
return {};
}
Result load(ImageLoader* loader)

View file

@ -106,33 +106,14 @@ bool RenderPath::bounds(Matrix* m, float* x, float* y, float* w, float* h)
void RenderRegion::intersect(const RenderRegion& rhs)
{
auto x1 = x + w;
auto y1 = y + h;
auto x2 = rhs.x + rhs.w;
auto y2 = rhs.y + rhs.h;
if (min.x < rhs.min.x) min.x = rhs.min.x;
if (min.y < rhs.min.y) min.y = rhs.min.y;
if (max.x > rhs.max.x) max.x = rhs.max.x;
if (max.y > rhs.max.y) max.y = rhs.max.y;
x = (x > rhs.x) ? x : rhs.x;
y = (y > rhs.y) ? y : rhs.y;
w = ((x1 < x2) ? x1 : x2) - x;
h = ((y1 < y2) ? y1 : y2) - y;
if (w < 0) w = 0;
if (h < 0) h = 0;
}
void RenderRegion::add(const RenderRegion& rhs)
{
if (rhs.x < x) {
w += (x - rhs.x);
x = rhs.x;
}
if (rhs.y < y) {
h += (y - rhs.y);
y = rhs.y;
}
if (rhs.x + rhs.w > x + w) w = (rhs.x + rhs.w) - x;
if (rhs.y + rhs.h > y + h) h = (rhs.y + rhs.h) - y;
// Not intersected: collapse to zero-area region
if (max.x < min.x) max.x = min.x;
if (max.y < min.y) max.y = min.y;
}
/************************************************************************/

View file

@ -94,16 +94,47 @@ struct RenderCompositor
struct RenderRegion
{
int32_t x, y, w, h;
struct {
int32_t x, y;
} min;
struct {
int32_t x, y;
} max;
static constexpr RenderRegion intersect(const RenderRegion& lhs, const RenderRegion& rhs)
{
return {{std::max(lhs.min.x, rhs.min.x), std::max(lhs.min.y, rhs.min.y)}, {std::min(lhs.max.x, rhs.max.x), std::min(lhs.max.y, rhs.max.y)}};
}
void intersect(const RenderRegion& rhs);
void add(const RenderRegion& rhs);
void add(const RenderRegion& rhs)
{
if (rhs.min.x < min.x) min.x = rhs.min.x;
if (rhs.min.y < min.y) min.y = rhs.min.y;
if (rhs.max.x > max.x) max.x = rhs.max.x;
if (rhs.max.y > max.y) max.y = rhs.max.y;
}
bool operator==(const RenderRegion& rhs) const
{
if (x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h) return true;
return false;
return (min.x == rhs.min.x && min.y == rhs.min.y && max.x == rhs.max.x && max.y == rhs.max.y);
}
void reset() { min.x = min.y = max.x = max.y = 0; }
bool valid() const { return (max.x > min.x && max.y > min.y); }
bool invalid() const { return !valid(); }
int32_t sx() const { return min.x; }
int32_t sy() const { return min.y; }
int32_t sw() const { return max.x - min.x; }
int32_t sh() const { return max.y - min.y; }
uint32_t x() const { return (uint32_t) sx(); }
uint32_t y() const { return (uint32_t) sy(); }
uint32_t w() const { return (uint32_t) sw(); }
uint32_t h() const { return (uint32_t) sh(); }
};
struct RenderPath
@ -272,7 +303,7 @@ struct RenderShape
struct RenderEffect
{
RenderData rd = nullptr;
RenderRegion extend = {0, 0, 0, 0};
RenderRegion extend{};
SceneEffect type;
bool valid = false;

View file

@ -64,7 +64,7 @@ struct SceneImpl : Scene
{
Paint::Impl impl;
list<Paint*> paints; //children list
RenderRegion vport = {0, 0, INT32_MAX, INT32_MAX};
RenderRegion vport = {};
Array<RenderEffect*>* effects = nullptr;
uint8_t compFlag = CompositionFlag::Invalid;
uint8_t opacity; //for composition
@ -159,40 +159,34 @@ struct SceneImpl : Scene
RenderRegion bounds(RenderMethod* renderer) const
{
if (paints.empty()) return {0, 0, 0, 0};
int32_t x1 = INT32_MAX;
int32_t y1 = INT32_MAX;
int32_t x2 = 0;
int32_t y2 = 0;
if (paints.empty()) return {};
//Merge regions
RenderRegion pRegion = {{INT32_MAX, INT32_MAX}, {0, 0}};
for (auto paint : paints) {
auto region = paint->pImpl->bounds(renderer);
//Merge regions
if (region.x < x1) x1 = region.x;
if (x2 < region.x + region.w) x2 = (region.x + region.w);
if (region.y < y1) y1 = region.y;
if (y2 < region.y + region.h) y2 = (region.y + region.h);
if (region.min.x < pRegion.min.x) pRegion.min.x = region.min.x;
if (pRegion.max.x < region.max.x) pRegion.max.x = region.max.x;
if (region.min.y < pRegion.min.y) pRegion.min.y = region.min.y;
if (pRegion.max.y < region.max.y) pRegion.max.y = region.max.y;
}
//Extends the render region if post effects require
int32_t ex = 0, ey = 0, ew = 0, eh = 0;
RenderRegion eRegion{};
if (effects) {
ARRAY_FOREACH(p, *effects) {
auto effect = *p;
if (effect->valid && renderer->region(effect)) {
ex = std::min(ex, effect->extend.x);
ey = std::min(ey, effect->extend.y);
ew = std::max(ew, effect->extend.w);
eh = std::max(eh, effect->extend.h);
}
if (effect->valid && renderer->region(effect)) eRegion.add(effect->extend);
}
}
auto ret = RenderRegion{x1 + ex, y1 + ey, (x2 - x1) + ew, (y2 - y1) + eh};
ret.intersect(this->vport);
return ret;
pRegion.min.x += eRegion.min.x;
pRegion.min.y += eRegion.min.y;
pRegion.max.x += eRegion.max.x;
pRegion.max.y += eRegion.max.y;
pRegion.intersect(this->vport);
return pRegion;
}
Result bounds(Point* pt4, Matrix& m, bool obb, bool stroking)

View file

@ -114,7 +114,7 @@ struct ShapeImpl : Shape
RenderRegion bounds(RenderMethod* renderer)
{
if (!impl.rd) return {0, 0, 0, 0};
if (!impl.rd) return {};
return renderer->region(impl.rd);
}

View file

@ -54,7 +54,7 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
if (!renderer) return Result::MemoryCorruption;
if (!renderer->target(buffer, stride, w, h, cs)) return Result::InvalidArguments;
pImpl->vport = {0, 0, (int32_t)w, (int32_t)h};
pImpl->vport = {{0, 0}, {(int32_t)w, (int32_t)h}};
renderer->viewport(pImpl->vport);
//FIXME: The value must be associated with an individual canvas instance.

View file

@ -55,7 +55,7 @@ Result WgCanvas::target(void* device, void* instance, void* target, uint32_t w,
if (!renderer) return Result::MemoryCorruption;
if (!renderer->target((WGPUDevice)device, (WGPUInstance)instance, target, w, h, type)) return Result::Unknown;
pImpl->vport = {0, 0, (int32_t)w, (int32_t)h};
pImpl->vport = {{0, 0}, {(int32_t)w, (int32_t)h}};
renderer->viewport(pImpl->vport);
//Paints must be updated again with this new target.

View file

@ -117,18 +117,13 @@ void WgCompositor::resize(WgContext& context, uint32_t width, uint32_t height) {
RenderRegion WgCompositor::shrinkRenderRegion(RenderRegion& rect)
{
// cut viewport to screen dimensions
int32_t xmin = std::max(0, std::min((int32_t)width, rect.x));
int32_t ymin = std::max(0, std::min((int32_t)height, rect.y));
int32_t xmax = std::max(xmin, std::min((int32_t)width, rect.x + rect.w));
int32_t ymax = std::max(ymin, std::min((int32_t)height, rect.y + rect.h));
return { xmin, ymin, xmax - xmin, ymax - ymin };
return RenderRegion::intersect(rect, {{0, 0}, {(int32_t)width, (int32_t)height}});
}
void WgCompositor::copyTexture(const WgRenderStorage* dst, const WgRenderStorage* src)
{
const RenderRegion region = { 0, 0, (int32_t)src->width, (int32_t)src->height };
const RenderRegion region = {{0, 0}, {(int32_t)src->width, (int32_t)src->height}};
copyTexture(dst, src, region);
}
@ -138,9 +133,9 @@ void WgCompositor::copyTexture(const WgRenderStorage* dst, const WgRenderStorage
assert(dst);
assert(src);
assert(commandEncoder);
const WGPUImageCopyTexture texSrc { .texture = src->texture, .origin = { .x = (uint32_t)region.x, .y = (uint32_t)region.y } };
const WGPUImageCopyTexture texDst { .texture = dst->texture, .origin = { .x = (uint32_t)region.x, .y = (uint32_t)region.y } };
const WGPUExtent3D copySize { .width = (uint32_t)region.w, .height = (uint32_t)region.h, .depthOrArrayLayers = 1 };
const WGPUImageCopyTexture texSrc { .texture = src->texture, .origin = { .x = region.x(), .y = region.y() } };
const WGPUImageCopyTexture texDst { .texture = dst->texture, .origin = { .x = region.x(), .y = region.y() } };
const WGPUExtent3D copySize { .width = region.w(), .height = region.h(), .depthOrArrayLayers = 1 };
wgpuCommandEncoderCopyTextureToTexture(commandEncoder, &texSrc, &texDst, &copySize);
}
@ -257,7 +252,7 @@ void WgCompositor::composeScene(WgContext& context, WgRenderStorage* src, WgRend
assert(mask);
assert(renderPassEncoder);
RenderRegion rect = shrinkRenderRegion(cmp->aabb);
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x, rect.y, rect.w, rect.h);
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x(), rect.y(), rect.w(), rect.h());
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, src->bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, mask->bindGroupTexure, 0, nullptr);
@ -293,10 +288,8 @@ void WgCompositor::drawShape(WgContext& context, WgRenderDataShape* renderData)
assert(renderData);
assert(renderPassEncoder);
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
if (renderData->renderSettingsShape.skip) return;
if (renderData->meshGroupShapes.meshes.count == 0) return;
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
if (renderData->renderSettingsShape.skip || renderData->meshGroupShapes.meshes.count == 0 || renderData->viewport.invalid()) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
// setup stencil rules
WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
@ -331,16 +324,14 @@ void WgCompositor::blendShape(WgContext& context, WgRenderDataShape* renderData,
assert(renderData);
assert(renderPassEncoder);
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
if (renderData->renderSettingsShape.skip) return;
if (renderData->meshGroupShapes.meshes.count == 0) return;
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
if (renderData->renderSettingsShape.skip || renderData->meshGroupShapes.meshes.count == 0 || renderData->viewport.invalid()) return;
// copy current render target data to dst storage
WgRenderStorage *target = currentTarget;
endRenderPass();
copyTexture(&storageTemp0, target);
beginRenderPass(commandEncoder, target, false);
// render shape with blend settings
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
// setup stencil rules
WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
@ -377,10 +368,9 @@ void WgCompositor::clipShape(WgContext& context, WgRenderDataShape* renderData)
assert(renderData);
assert(renderPassEncoder);
assert(renderData->meshGroupShapes.meshes.count == renderData->meshGroupShapesBBox.meshes.count);
if (renderData->renderSettingsShape.skip) return;
if (renderData->meshGroupShapes.meshes.count == 0) return;
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
if (renderData->renderSettingsShape.skip || renderData->meshGroupShapes.meshes.count == 0 || renderData->viewport.invalid()) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
// setup stencil rules
WGPURenderPipeline stencilPipeline = (renderData->fillRule == FillRule::NonZero) ? pipelines.nonzero : pipelines.evenodd;
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
@ -420,10 +410,9 @@ void WgCompositor::drawStrokes(WgContext& context, WgRenderDataShape* renderData
assert(renderData);
assert(renderPassEncoder);
assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count);
if (renderData->renderSettingsStroke.skip) return;
if (renderData->meshGroupStrokes.meshes.count == 0) return;
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
if (renderData->renderSettingsStroke.skip || renderData->meshGroupStrokes.meshes.count == 0 || renderData->viewport.invalid()) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
// draw strokes to stencil (first pass)
for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) {
// setup stencil rules
@ -459,15 +448,14 @@ void WgCompositor::blendStrokes(WgContext& context, WgRenderDataShape* renderDat
assert(renderData);
assert(renderPassEncoder);
assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count);
if (renderData->renderSettingsStroke.skip) return;
if (renderData->meshGroupStrokes.meshes.count == 0) return;
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
if (renderData->renderSettingsStroke.skip || renderData->meshGroupStrokes.meshes.count == 0 || renderData->viewport.invalid()) return;
// copy current render target data to dst storage
WgRenderStorage *target = currentTarget;
endRenderPass();
copyTexture(&storageTemp0, target);
beginRenderPass(commandEncoder, target, false);
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
// draw strokes to stencil (first pass)
for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) {
// setup stencil rules
@ -507,8 +495,8 @@ void WgCompositor::clipStrokes(WgContext& context, WgRenderDataShape* renderData
assert(renderData->meshGroupStrokes.meshes.count == renderData->meshGroupStrokesBBox.meshes.count);
if (renderData->renderSettingsStroke.skip) return;
if (renderData->meshGroupStrokes.meshes.count == 0) return;
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
if (renderData->viewport.invalid()) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
// draw strokes to stencil (first pass)
for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) {
// setup stencil rules
@ -548,8 +536,8 @@ void WgCompositor::drawImage(WgContext& context, WgRenderDataPicture* renderData
{
assert(renderData);
assert(renderPassEncoder);
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
if (renderData->viewport.invalid()) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
// draw stencil
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
@ -570,8 +558,8 @@ void WgCompositor::blendImage(WgContext& context, WgRenderDataPicture* renderDat
{
assert(renderData);
assert(renderPassEncoder);
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
if (renderData->viewport.invalid()) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
// copy current render target data to dst storage
WgRenderStorage *target = currentTarget;
endRenderPass();
@ -599,8 +587,8 @@ void WgCompositor::clipImage(WgContext& context, WgRenderDataPicture* renderData
{
assert(renderData);
assert(renderPassEncoder);
if ((renderData->viewport.w <= 0) || (renderData->viewport.h <= 0)) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x, renderData->viewport.y, renderData->viewport.w, renderData->viewport.h);
if (renderData->viewport.invalid()) return;
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, renderData->viewport.x(), renderData->viewport.y(), renderData->viewport.w(), renderData->viewport.h());
// setup stencil rules
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, bindGroupViewMat, 0, nullptr);
@ -629,7 +617,7 @@ void WgCompositor::drawScene(WgContext& context, WgRenderStorage* scene, WgCompo
assert(currentTarget);
// draw scene
RenderRegion rect = shrinkRenderRegion(compose->aabb);
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x, rect.y, rect.w, rect.h);
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x(), rect.y(), rect.w(), rect.h());
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, scene->bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, bindGroupOpacities[compose->opacity], 0, nullptr);
@ -651,7 +639,7 @@ void WgCompositor::blendScene(WgContext& context, WgRenderStorage* scene, WgComp
// blend scene
uint32_t blendMethodInd = (uint32_t)compose->blend;
RenderRegion rect = shrinkRenderRegion(compose->aabb);
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x, rect.y, rect.w, rect.h);
wgpuRenderPassEncoderSetScissorRect(renderPassEncoder, rect.x(), rect.y(), rect.w(), rect.h());
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 0, scene->bindGroupTexure, 0, nullptr);
wgpuRenderPassEncoderSetBindGroup(renderPassEncoder, 1, storageTemp0.bindGroupTexure, 0, nullptr);
@ -784,7 +772,7 @@ bool WgCompositor::gaussianBlur(WgContext& context, WgRenderStorage* dst, const
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, renderData->bindGroupParams, 0, nullptr);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 3, viewport->bindGroupViewport, 0, nullptr);
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelines.gaussian_horz);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (aabb.w - 1) / 128 + 1, aabb.h, 1);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (aabb.sw() - 1) / 128 + 1, aabb.sh(), 1);
std::swap(sbuff, dbuff);
}
// vertical blur
@ -794,7 +782,7 @@ bool WgCompositor::gaussianBlur(WgContext& context, WgRenderStorage* dst, const
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, renderData->bindGroupParams, 0, nullptr);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 3, viewport->bindGroupViewport, 0, nullptr);
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelines.gaussian_vert);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, aabb.w, (aabb.h - 1) / 128 + 1, 1);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, aabb.sw(), (aabb.sh() - 1) / 128 + 1, 1);
std::swap(sbuff, dbuff);
}
}
@ -834,7 +822,7 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const Re
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, renderDataParams->bindGroupParams, 0, nullptr);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 3, viewport->bindGroupViewport, 0, nullptr);
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelines.gaussian_horz);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (aabb.w - 1) / 128 + 1, aabb.h, 1);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (aabb.sw() - 1) / 128 + 1, aabb.h(), 1);
std::swap(sbuff, dbuff);
// vertical blur
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 0, sbuff->bindGroupRead, 0, nullptr);
@ -842,7 +830,7 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const Re
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, renderDataParams->bindGroupParams, 0, nullptr);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 3, viewport->bindGroupViewport, 0, nullptr);
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelines.gaussian_vert);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, aabb.w, (aabb.h - 1) / 128 + 1, 1);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, aabb.sw(), (aabb.sh() - 1) / 128 + 1, 1);
std::swap(sbuff, dbuff);
wgpuComputePassEncoderEnd(computePassEncoder);
wgpuComputePassEncoderRelease(computePassEncoder);
@ -857,7 +845,7 @@ bool WgCompositor::dropShadow(WgContext& context, WgRenderStorage* dst, const Re
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, renderDataParams->bindGroupParams, 0, nullptr);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 3, viewport->bindGroupViewport, 0, nullptr);
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelines.dropshadow);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (aabb.w - 1) / 128 + 1, aabb.h, 1);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (aabb.sw() - 1) / 128 + 1, aabb.h(), 1);
wgpuComputePassEncoderEnd(computePassEncoder);
wgpuComputePassEncoderRelease(computePassEncoder);
}
@ -882,7 +870,7 @@ bool WgCompositor::fillEffect(WgContext& context, WgRenderStorage* dst, const Re
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, static_cast<WgRenderDataEffectParams*>(params->rd)->bindGroupParams, 0, nullptr);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 3, compose->rdViewport->bindGroupViewport, 0, nullptr);
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelines.fill_effect);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (compose->aabb.w - 1) / 128 + 1, compose->aabb.h, 1);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (compose->aabb.sw() - 1) / 128 + 1, compose->aabb.sh(), 1);
wgpuComputePassEncoderEnd(computePassEncoder);
wgpuComputePassEncoderRelease(computePassEncoder);
@ -906,7 +894,7 @@ bool WgCompositor::tintEffect(WgContext& context, WgRenderStorage* dst, const Re
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, static_cast<WgRenderDataEffectParams*>(params->rd)->bindGroupParams, 0, nullptr);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 3, compose->rdViewport->bindGroupViewport, 0, nullptr);
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelines.tint_effect);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (compose->aabb.w - 1) / 128 + 1, compose->aabb.h, 1);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (compose->aabb.sw() - 1) / 128 + 1, compose->aabb.sh(), 1);
wgpuComputePassEncoderEnd(computePassEncoder);
wgpuComputePassEncoderRelease(computePassEncoder);
@ -929,7 +917,7 @@ bool WgCompositor::tritoneEffect(WgContext& context, WgRenderStorage* dst, const
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 2, static_cast<WgRenderDataEffectParams*>(params->rd)->bindGroupParams, 0, nullptr);
wgpuComputePassEncoderSetBindGroup(computePassEncoder, 3, compose->rdViewport->bindGroupViewport, 0, nullptr);
wgpuComputePassEncoderSetPipeline(computePassEncoder, pipelines.tritone_effect);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (compose->aabb.w - 1) / 128 + 1, compose->aabb.h, 1);
wgpuComputePassEncoderDispatchWorkgroups(computePassEncoder, (compose->aabb.sw() - 1) / 128 + 1, compose->aabb.sh(), 1);
wgpuComputePassEncoderEnd(computePassEncoder);
wgpuComputePassEncoderRelease(computePassEncoder);

View file

@ -259,14 +259,9 @@ RenderRegion WgRenderer::region(RenderData data)
if (renderData->type() == Type::Shape) {
auto& v1 = renderData->aabb.min;
auto& v2 = renderData->aabb.max;
RenderRegion renderRegion;
renderRegion.x = static_cast<int32_t>(nearbyint(v1.x));
renderRegion.y = static_cast<int32_t>(nearbyint(v1.y));
renderRegion.w = static_cast<int32_t>(nearbyint(v2.x)) - renderRegion.x;
renderRegion.h = static_cast<int32_t>(nearbyint(v2.y)) - renderRegion.y;
return renderRegion;
return {{int32_t(nearbyint(v1.x)), int32_t(nearbyint(v1.y))}, {int32_t(nearbyint(v2.x)), int32_t(nearbyint(v2.y))}};
}
return { 0, 0, (int32_t)mTargetSurface.w, (int32_t)mTargetSurface.h };
return {{0, 0}, {(int32_t)mTargetSurface.w, (int32_t)mTargetSurface.h}};
}
@ -586,12 +581,12 @@ bool WgRenderer::region(RenderEffect* effect)
auto gaussian = (RenderEffectGaussianBlur*)effect;
auto renderData = (WgRenderDataEffectParams*)gaussian->rd;
if (gaussian->direction != 2) {
gaussian->extend.x = -renderData->extend;
gaussian->extend.w = +renderData->extend * 2;
gaussian->extend.min.x = -renderData->extend;
gaussian->extend.max.x = +renderData->extend;
}
if (gaussian->direction != 1) {
gaussian->extend.y = -renderData->extend;
gaussian->extend.h = +renderData->extend * 2;
gaussian->extend.min.y = -renderData->extend;
gaussian->extend.max.y = +renderData->extend;
}
return true;
} else
@ -599,10 +594,10 @@ bool WgRenderer::region(RenderEffect* effect)
if (effect->type == SceneEffect::DropShadow) {
auto dropShadow = (RenderEffectDropShadow*)effect;
auto renderData = (WgRenderDataEffectParams*)dropShadow->rd;
dropShadow->extend.x = -(renderData->extend + std::abs(renderData->offset.x));
dropShadow->extend.w = +(renderData->extend + std::abs(renderData->offset.x)) * 2;
dropShadow->extend.y = -(renderData->extend + std::abs(renderData->offset.y));
dropShadow->extend.h = +(renderData->extend + std::abs(renderData->offset.y)) * 2;
dropShadow->extend.min.x = -(renderData->extend + std::abs(renderData->offset.x));
dropShadow->extend.max.x = +(renderData->extend + std::abs(renderData->offset.x));
dropShadow->extend.min.y = -(renderData->extend + std::abs(renderData->offset.y));
dropShadow->extend.max.y = +(renderData->extend + std::abs(renderData->offset.y));
return true;
}
return false;

View file

@ -118,10 +118,10 @@ void WgShaderTypeVec4f::update(const RenderColor& c)
void WgShaderTypeVec4f::update(const RenderRegion& r)
{
vec[0] = r.x; // left
vec[1] = r.y; // top
vec[2] = r.x + r.w - 1; // right
vec[3] = r.y + r.h - 1; // bottom
vec[0] = r.min.x;
vec[1] = r.min.y;
vec[2] = r.max.x - 1;
vec[3] = r.max.y - 1;
}
//************************************************************************