mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 00:05:36 +00:00
Bug 1679215 - limit SWGL compositing to dirty region. r=mattwoodrow
Differential Revision: https://phabricator.services.mozilla.com/D101256
This commit is contained in:
parent
8bee9f98ac
commit
50180b37c8
@ -571,7 +571,8 @@ bool RenderCompositorNativeSWGL::InitDefaultFramebuffer(
|
||||
if (!MapNativeLayer(mNativeLayerForEntireWindow, aBounds, aBounds)) {
|
||||
return false;
|
||||
}
|
||||
wr_swgl_init_default_framebuffer(mContext, aBounds.width, aBounds.height,
|
||||
wr_swgl_init_default_framebuffer(mContext, aBounds.x, aBounds.y,
|
||||
aBounds.width, aBounds.height,
|
||||
mLayerStride, mLayerValidRectData);
|
||||
}
|
||||
return true;
|
||||
|
@ -45,10 +45,17 @@ bool RenderCompositorSWGL::MakeCurrent() {
|
||||
}
|
||||
|
||||
bool RenderCompositorSWGL::BeginFrame() {
|
||||
// Request a new draw target to use from the widget...
|
||||
// Set up a temporary region representing the entire window surface in case a
|
||||
// dirty region is not supplied.
|
||||
ClearMappedBuffer();
|
||||
LayoutDeviceIntRect bounds(LayoutDeviceIntPoint(), GetBufferSize());
|
||||
mRegion = LayoutDeviceIntRegion(bounds);
|
||||
mRegion = LayoutDeviceIntRect(LayoutDeviceIntPoint(), GetBufferSize());
|
||||
wr_swgl_make_current(mContext);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenderCompositorSWGL::AllocateMappedBuffer() {
|
||||
// Request a new draw target to use from the widget...
|
||||
MOZ_ASSERT(!mDT);
|
||||
layers::BufferMode bufferMode = layers::BufferMode::BUFFERED;
|
||||
mDT = mWidget->StartRemoteDrawingInRegion(mRegion, &bufferMode);
|
||||
if (!mDT) {
|
||||
@ -62,18 +69,24 @@ bool RenderCompositorSWGL::BeginFrame() {
|
||||
int32_t stride = 0;
|
||||
gfx::SurfaceFormat format = gfx::SurfaceFormat::UNKNOWN;
|
||||
if (!mSurface && mDT->LockBits(&data, &size, &stride, &format) &&
|
||||
(size != bounds.Size().ToUnknownSize() ||
|
||||
(format != gfx::SurfaceFormat::B8G8R8A8 &&
|
||||
format != gfx::SurfaceFormat::B8G8R8X8))) {
|
||||
(format != gfx::SurfaceFormat::B8G8R8A8 &&
|
||||
format != gfx::SurfaceFormat::B8G8R8X8)) {
|
||||
// We tried to lock the DT and it succeeded, but the size or format
|
||||
// of the data is not compatible, so just release it and fall back below...
|
||||
mDT->ReleaseBits(data);
|
||||
data = nullptr;
|
||||
}
|
||||
LayoutDeviceIntRect bounds = mRegion.GetBounds();
|
||||
// If locking succeeded above, just use that.
|
||||
if (data) {
|
||||
mMappedData = data;
|
||||
mMappedStride = stride;
|
||||
// Disambiguate whether the widget's draw target has its origin at zero or
|
||||
// if it is offset to the dirty region origin.
|
||||
if (size == gfx::IntSize(bounds.XMost(), bounds.YMost())) {
|
||||
// Update the bounds to include zero if the origin is at zero.
|
||||
bounds.ExpandToEnclose(LayoutDeviceIntPoint(0, 0));
|
||||
}
|
||||
} else {
|
||||
// If we couldn't lock the DT above, then allocate a data surface and map
|
||||
// that for usage with SWGL.
|
||||
@ -93,13 +106,44 @@ bool RenderCompositorSWGL::BeginFrame() {
|
||||
mMappedStride = map.mStride;
|
||||
}
|
||||
MOZ_ASSERT(mMappedData != nullptr && mMappedStride > 0);
|
||||
wr_swgl_make_current(mContext);
|
||||
wr_swgl_init_default_framebuffer(mContext, bounds.width, bounds.height,
|
||||
mMappedStride, mMappedData);
|
||||
wr_swgl_init_default_framebuffer(mContext, bounds.x, bounds.y, bounds.width,
|
||||
bounds.height, mMappedStride, mMappedData);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderCompositorSWGL::CommitMappedBuffer() {
|
||||
void RenderCompositorSWGL::StartCompositing(
|
||||
const wr::DeviceIntRect* aDirtyRects, size_t aNumDirtyRects) {
|
||||
if (mDT) {
|
||||
// Cancel any existing buffers that might accidentally be left from updates
|
||||
CommitMappedBuffer(false);
|
||||
// Reset the region to the widget bounds
|
||||
mRegion = LayoutDeviceIntRect(LayoutDeviceIntPoint(), GetBufferSize());
|
||||
}
|
||||
if (aNumDirtyRects) {
|
||||
// Install the dirty rects into the bounds of the existing region
|
||||
auto bounds = mRegion.GetBounds();
|
||||
mRegion.SetEmpty();
|
||||
for (size_t i = 0; i < aNumDirtyRects; i++) {
|
||||
const auto& rect = aDirtyRects[i];
|
||||
mRegion.OrWith(LayoutDeviceIntRect(rect.origin.x, rect.origin.y,
|
||||
rect.size.width, rect.size.height));
|
||||
}
|
||||
// Ensure the region lies within the widget bounds
|
||||
mRegion.AndWith(bounds);
|
||||
}
|
||||
// Now that the dirty rects have been supplied and the composition region
|
||||
// is known, allocate and install a framebuffer encompassing the composition
|
||||
// region.
|
||||
if (!AllocateMappedBuffer()) {
|
||||
gfxCriticalNote
|
||||
<< "RenderCompositorSWGL failed mapping default framebuffer";
|
||||
// If allocation of the mapped default framebuffer failed, then just install
|
||||
// a small temporary framebuffer so compositing can still proceed.
|
||||
wr_swgl_init_default_framebuffer(mContext, 0, 0, 2, 2, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderCompositorSWGL::CommitMappedBuffer(bool aDirty) {
|
||||
if (!mDT) {
|
||||
return;
|
||||
}
|
||||
@ -109,13 +153,15 @@ void RenderCompositorSWGL::CommitMappedBuffer() {
|
||||
// If we're using a data surface, unmap it and draw it to the DT if there
|
||||
// are any supplied dirty rects.
|
||||
mSurface->Unmap();
|
||||
for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const LayoutDeviceIntRect& dirtyRect = iter.Get();
|
||||
gfx::Rect bounds(dirtyRect.x, dirtyRect.y, dirtyRect.width,
|
||||
dirtyRect.height);
|
||||
mDT->DrawSurface(mSurface, bounds, bounds,
|
||||
gfx::DrawSurfaceOptions(gfx::SamplingFilter::POINT),
|
||||
gfx::DrawOptions(1.0f, gfx::CompositionOp::OP_SOURCE));
|
||||
if (aDirty) {
|
||||
for (auto iter = mRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||
const LayoutDeviceIntRect& dirtyRect = iter.Get();
|
||||
gfx::Rect bounds(dirtyRect.x, dirtyRect.y, dirtyRect.width,
|
||||
dirtyRect.height);
|
||||
mDT->DrawSurface(mSurface, bounds, bounds,
|
||||
gfx::DrawSurfaceOptions(gfx::SamplingFilter::POINT),
|
||||
gfx::DrawOptions(1.0f, gfx::CompositionOp::OP_SOURCE));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Otherwise, we had locked the DT directly. Just release the data.
|
||||
@ -126,18 +172,13 @@ void RenderCompositorSWGL::CommitMappedBuffer() {
|
||||
ClearMappedBuffer();
|
||||
}
|
||||
|
||||
void RenderCompositorSWGL::CancelFrame() { CommitMappedBuffer(); }
|
||||
void RenderCompositorSWGL::CancelFrame() { CommitMappedBuffer(false); }
|
||||
|
||||
RenderedFrameId RenderCompositorSWGL::EndFrame(
|
||||
const nsTArray<DeviceIntRect>& aDirtyRects) {
|
||||
if (!aDirtyRects.IsEmpty()) {
|
||||
mRegion.SetEmpty();
|
||||
for (auto& rect : aDirtyRects) {
|
||||
mRegion.OrWith(LayoutDeviceIntRect(rect.origin.x, rect.origin.y,
|
||||
rect.size.width, rect.size.height));
|
||||
}
|
||||
}
|
||||
|
||||
// Dirty rects have already been set inside StartCompositing. We need to keep
|
||||
// those dirty rects exactly the same here so we supply the same exact region
|
||||
// to EndRemoteDrawingInRegion as for StartRemoteDrawingInRegion.
|
||||
RenderedFrameId frameId = GetNextRenderFrameId();
|
||||
CommitMappedBuffer();
|
||||
return frameId;
|
||||
|
@ -31,6 +31,9 @@ class RenderCompositorSWGL : public RenderCompositor {
|
||||
void CancelFrame() override;
|
||||
RenderedFrameId EndFrame(const nsTArray<DeviceIntRect>& aDirtyRects) final;
|
||||
|
||||
void StartCompositing(const wr::DeviceIntRect* aDirtyRects,
|
||||
size_t aNumDirtyRects) override;
|
||||
|
||||
bool UsePartialPresent() override { return true; }
|
||||
|
||||
void Pause() override;
|
||||
@ -62,7 +65,9 @@ class RenderCompositorSWGL : public RenderCompositor {
|
||||
|
||||
void ClearMappedBuffer();
|
||||
|
||||
void CommitMappedBuffer();
|
||||
bool AllocateMappedBuffer();
|
||||
|
||||
void CommitMappedBuffer(bool aDirty = true);
|
||||
};
|
||||
|
||||
} // namespace wr
|
||||
|
@ -42,12 +42,14 @@ pub extern "C" fn wr_swgl_make_current(ctx: *mut c_void) {
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_swgl_init_default_framebuffer(
|
||||
ctx: *mut c_void,
|
||||
x: i32,
|
||||
y: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
stride: i32,
|
||||
buf: *mut c_void,
|
||||
) {
|
||||
swgl::Context::from(ctx).init_default_framebuffer(width, height, stride, buf);
|
||||
swgl::Context::from(ctx).init_default_framebuffer(x, y, width, height, stride, buf);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@ -1583,9 +1585,6 @@ impl Compositor for SwCompositor {
|
||||
self.late_surfaces.clear();
|
||||
|
||||
self.reset_overlaps();
|
||||
if self.composite_thread.is_some() {
|
||||
self.locked_framebuffer = self.gl.lock_framebuffer(0);
|
||||
}
|
||||
}
|
||||
|
||||
fn add_surface(
|
||||
@ -1644,6 +1643,8 @@ impl Compositor for SwCompositor {
|
||||
}
|
||||
}
|
||||
|
||||
self.locked_framebuffer = self.gl.lock_framebuffer(0);
|
||||
|
||||
composite_thread.start_compositing();
|
||||
// Issue any initial composite jobs for the SwComposite thread.
|
||||
let mut lock = composite_thread.lock();
|
||||
|
@ -32,8 +32,7 @@ static NO_INLINE void scale_blit(Texture& srctex, const IntRect& srcReq,
|
||||
// Limit dest sampling bounds to overlap source bounds
|
||||
dstBounds.intersect(srcBounds);
|
||||
// Compute the clipped bounds, relative to dstBounds.
|
||||
IntRect clippedDest = dstBounds.intersection(clipRect);
|
||||
clippedDest.offset(-dstBounds.x0, -dstBounds.y0);
|
||||
IntRect clippedDest = dstBounds.intersection(clipRect) - dstBounds.origin();
|
||||
// Check if clipped sampling bounds are empty
|
||||
if (clippedDest.is_empty()) {
|
||||
return;
|
||||
@ -289,12 +288,12 @@ void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
|
||||
if (invertY) {
|
||||
swap(dstY0, dstY1);
|
||||
}
|
||||
IntRect srcReq = {srcX0, srcY0, srcX1, srcY1};
|
||||
IntRect dstReq = {dstX0, dstY0, dstX1, dstY1};
|
||||
IntRect clipRect = {0, 0, dstReq.width(), dstReq.height()};
|
||||
IntRect srcReq = IntRect{srcX0, srcY0, srcX1, srcY1} - srctex.offset;
|
||||
IntRect dstReq = IntRect{dstX0, dstY0, dstX1, dstY1} - dsttex.offset;
|
||||
if (srcReq.is_empty() || dstReq.is_empty()) {
|
||||
return;
|
||||
}
|
||||
IntRect clipRect = {0, 0, dstReq.width(), dstReq.height()};
|
||||
prepare_texture(srctex);
|
||||
prepare_texture(dsttex, &dstReq);
|
||||
if (!srcReq.same_size(dstReq) && srctex.width >= 2 && filter == GL_LINEAR &&
|
||||
@ -424,8 +423,10 @@ void Composite(LockedTexture* lockedDst, LockedTexture* lockedSrc, GLint srcX,
|
||||
assert(srctex.bpp() == 4);
|
||||
assert(dsttex.bpp() == 4);
|
||||
|
||||
IntRect srcReq = {srcX, srcY, srcX + srcWidth, srcY + srcHeight};
|
||||
IntRect dstReq = {dstX, dstY, dstX + dstWidth, dstY + dstHeight};
|
||||
IntRect srcReq =
|
||||
IntRect{srcX, srcY, srcX + srcWidth, srcY + srcHeight} - srctex.offset;
|
||||
IntRect dstReq =
|
||||
IntRect{dstX, dstY, dstX + dstWidth, dstY + dstHeight} - dsttex.offset;
|
||||
// Compute clip rect as relative to the dstReq, as that's the same coords
|
||||
// as used for the sampling bounds.
|
||||
IntRect clipRect = {clipX - dstX,
|
||||
@ -899,10 +900,13 @@ void CompositeYUV(LockedTexture* lockedDst, LockedTexture* lockedY,
|
||||
(ytex.bpp() == 2 && colorDepth > 8));
|
||||
// assert(ytex.width == utex.width && ytex.height == utex.height);
|
||||
assert(utex.width == vtex.width && utex.height == vtex.height);
|
||||
assert(ytex.offset == utex.offset && ytex.offset == vtex.offset);
|
||||
assert(dsttex.bpp() == 4);
|
||||
|
||||
IntRect srcReq = {srcX, srcY, srcX + srcWidth, srcY + srcHeight};
|
||||
IntRect dstReq = {dstX, dstY, dstX + dstWidth, dstY + dstHeight};
|
||||
IntRect srcReq =
|
||||
IntRect{srcX, srcY, srcX + srcWidth, srcY + srcHeight} - ytex.offset;
|
||||
IntRect dstReq =
|
||||
IntRect{dstX, dstY, dstX + dstWidth, dstY + dstHeight} - dsttex.offset;
|
||||
// Compute clip rect as relative to the dstReq, as that's the same coords
|
||||
// as used for the sampling bounds.
|
||||
IntRect clipRect = {clipX - dstX,
|
||||
|
@ -80,6 +80,8 @@
|
||||
|
||||
using namespace glsl;
|
||||
|
||||
typedef ivec2_scalar IntPoint;
|
||||
|
||||
struct IntRect {
|
||||
int x0;
|
||||
int y0;
|
||||
@ -90,6 +92,8 @@ struct IntRect {
|
||||
int height() const { return y1 - y0; }
|
||||
bool is_empty() const { return width() <= 0 || height() <= 0; }
|
||||
|
||||
IntPoint origin() const { return IntPoint(x0, y0); }
|
||||
|
||||
bool same_size(const IntRect& o) const {
|
||||
return width() == o.width() && height() == o.height();
|
||||
}
|
||||
@ -129,13 +133,20 @@ struct IntRect {
|
||||
swap(y0, y1);
|
||||
}
|
||||
|
||||
IntRect& offset(int dx, int dy) {
|
||||
x0 += dx;
|
||||
y0 += dy;
|
||||
x1 += dx;
|
||||
y1 += dy;
|
||||
IntRect& offset(const IntPoint& o) {
|
||||
x0 += o.x;
|
||||
y0 += o.y;
|
||||
x1 += o.x;
|
||||
y1 += o.y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
IntRect operator+(const IntPoint& o) const {
|
||||
return IntRect(*this).offset(o);
|
||||
}
|
||||
IntRect operator-(const IntPoint& o) const {
|
||||
return IntRect(*this).offset(-o);
|
||||
}
|
||||
};
|
||||
|
||||
struct VertexAttrib {
|
||||
@ -535,6 +546,10 @@ struct Texture {
|
||||
// locks, we need to disallow modifying or destroying the texture as it may
|
||||
// be accessed by other threads where modifications could lead to races.
|
||||
int32_t locked = 0;
|
||||
// When used as an attachment of a framebuffer, rendering to the texture
|
||||
// behaves as if it is located at the given offset such that the offset is
|
||||
// subtracted from all transformed vertexes after the viewport is applied.
|
||||
IntPoint offset;
|
||||
|
||||
enum FLAGS {
|
||||
// If the buffer is internally-allocated by SWGL
|
||||
@ -684,10 +699,11 @@ struct Texture {
|
||||
~Texture() { cleanup(); }
|
||||
|
||||
IntRect bounds() const { return IntRect{0, 0, width, height}; }
|
||||
IntRect offset_bounds() const { return bounds() + offset; }
|
||||
|
||||
// Find the valid sampling bounds relative to the requested region
|
||||
IntRect sample_bounds(const IntRect& req, bool invertY = false) const {
|
||||
IntRect bb = bounds().intersect(req).offset(-req.x0, -req.y0);
|
||||
IntRect bb = bounds().intersect(req) - req.origin();
|
||||
if (invertY) bb.invert_y(req.height());
|
||||
return bb;
|
||||
}
|
||||
@ -965,8 +981,13 @@ struct Context {
|
||||
return textures[texture_units[unit].texture_rectangle_binding];
|
||||
}
|
||||
|
||||
IntRect apply_scissor(IntRect bb) const {
|
||||
return scissortest ? bb.intersect(scissor) : bb;
|
||||
IntRect apply_scissor(IntRect bb,
|
||||
const IntPoint& origin = IntPoint(0, 0)) const {
|
||||
return scissortest ? bb.intersect(scissor - origin) : bb;
|
||||
}
|
||||
|
||||
IntRect apply_scissor(const Texture& t) const {
|
||||
return apply_scissor(t.bounds(), t.offset);
|
||||
}
|
||||
};
|
||||
static Context* ctx = nullptr;
|
||||
@ -2345,7 +2366,7 @@ static void clear_buffer(Texture& t, T value, int layer, IntRect bb,
|
||||
|
||||
template <typename T>
|
||||
static inline void clear_buffer(Texture& t, T value, int layer = 0) {
|
||||
IntRect bb = ctx->apply_scissor(t.bounds());
|
||||
IntRect bb = ctx->apply_scissor(t);
|
||||
if (bb.width() > 0) {
|
||||
clear_buffer<T>(t, value, layer, bb);
|
||||
}
|
||||
@ -2439,7 +2460,7 @@ static void prepare_texture(Texture& t, const IntRect* skip) {
|
||||
}
|
||||
|
||||
static inline bool clear_requires_scissor(Texture& t) {
|
||||
return ctx->scissortest && !ctx->scissor.contains(t.bounds());
|
||||
return ctx->scissortest && !ctx->scissor.contains(t.offset_bounds());
|
||||
}
|
||||
|
||||
// Setup a clear on a texture. This may either force an immediate clear or
|
||||
@ -2449,7 +2470,8 @@ static void request_clear(Texture& t, int layer, T value) {
|
||||
// If the clear would require a scissor, force clear anything outside
|
||||
// the scissor, and then immediately clear anything inside the scissor.
|
||||
if (clear_requires_scissor(t)) {
|
||||
force_clear<T>(t, &ctx->scissor);
|
||||
IntRect skip = ctx->scissor - t.offset;
|
||||
force_clear<T>(t, &skip);
|
||||
clear_buffer<T>(t, value, layer);
|
||||
} else if (t.depth > 1) {
|
||||
// Delayed clear is not supported on texture arrays.
|
||||
@ -2483,7 +2505,7 @@ static ALWAYS_INLINE void fill_depth_run(DepthRun* dst, size_t n,
|
||||
void Texture::fill_depth_runs(uint16_t depth) {
|
||||
if (!buf) return;
|
||||
assert(cleared());
|
||||
IntRect bb = ctx->apply_scissor(bounds());
|
||||
IntRect bb = ctx->apply_scissor(*this);
|
||||
DepthRun* runs = (DepthRun*)sample_ptr(0, bb.y0);
|
||||
for (int rows = bb.height(); rows > 0; rows--) {
|
||||
if (bb.width() >= width) {
|
||||
@ -2504,7 +2526,8 @@ void Texture::fill_depth_runs(uint16_t depth) {
|
||||
|
||||
extern "C" {
|
||||
|
||||
void InitDefaultFramebuffer(int width, int height, int stride, void* buf) {
|
||||
void InitDefaultFramebuffer(int x, int y, int width, int height, int stride,
|
||||
void* buf) {
|
||||
Framebuffer& fb = ctx->framebuffers[0];
|
||||
if (!fb.color_attachment) {
|
||||
GenTextures(1, &fb.color_attachment);
|
||||
@ -2514,12 +2537,14 @@ void InitDefaultFramebuffer(int width, int height, int stride, void* buf) {
|
||||
// the underlying storage for the color buffer texture.
|
||||
Texture& colortex = ctx->textures[fb.color_attachment];
|
||||
set_tex_storage(colortex, GL_RGBA8, width, height, buf, stride);
|
||||
colortex.offset = IntPoint(x, y);
|
||||
if (!fb.depth_attachment) {
|
||||
GenTextures(1, &fb.depth_attachment);
|
||||
}
|
||||
// Ensure dimensions of the depth buffer match the color buffer.
|
||||
Texture& depthtex = ctx->textures[fb.depth_attachment];
|
||||
set_tex_storage(depthtex, GL_DEPTH_COMPONENT16, width, height);
|
||||
depthtex.offset = IntPoint(x, y);
|
||||
}
|
||||
|
||||
void* GetColorBuffer(GLuint fbo, GLboolean flush, int32_t* width,
|
||||
@ -2532,6 +2557,7 @@ void* GetColorBuffer(GLuint fbo, GLboolean flush, int32_t* width,
|
||||
if (flush) {
|
||||
prepare_texture(colortex);
|
||||
}
|
||||
assert(colortex.offset == IntPoint(0, 0));
|
||||
*width = colortex.width;
|
||||
*height = colortex.height;
|
||||
*stride = colortex.stride();
|
||||
@ -2625,6 +2651,9 @@ void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
|
||||
prepare_texture(t);
|
||||
// debugf("read pixels %d, %d, %d, %d from fb %d with format %x\n", x, y,
|
||||
// width, height, ctx->read_framebuffer_binding, t.internal_format);
|
||||
x -= t.offset.x;
|
||||
y -= t.offset.y;
|
||||
assert(x >= 0 && y >= 0);
|
||||
assert(x + width <= t.width);
|
||||
assert(y + height <= t.height);
|
||||
if (internal_format_for_data(format, type) != t.internal_format) {
|
||||
@ -3109,7 +3138,7 @@ struct ClipRect {
|
||||
float y1;
|
||||
|
||||
ClipRect(const IntRect& i) : x0(i.x0), y0(i.y0), x1(i.x1), y1(i.y1) {}
|
||||
ClipRect(Texture& t) : ClipRect(ctx->apply_scissor(t.bounds())) {}
|
||||
ClipRect(const Texture& t) : ClipRect(ctx->apply_scissor(t)) {}
|
||||
|
||||
template <typename P>
|
||||
bool overlaps(int nump, const P* p) const {
|
||||
@ -3920,7 +3949,8 @@ static void draw_perspective(int nump, Interpolants interp_outs[4],
|
||||
vec3_scalar scale =
|
||||
vec3_scalar(ctx->viewport.width(), ctx->viewport.height(), 1) * 0.5f;
|
||||
vec3_scalar offset =
|
||||
vec3_scalar(ctx->viewport.x0, ctx->viewport.y0, 0.0f) + scale;
|
||||
make_vec3(make_vec2(ctx->viewport.origin() - colortex.offset), 0.0f) +
|
||||
scale;
|
||||
if (test_none(pos.z <= -pos.w || pos.z >= pos.w)) {
|
||||
// No points cross the near or far planes, so no clipping required.
|
||||
// Just divide coords by W and convert to viewport. We assume the W
|
||||
@ -4017,7 +4047,7 @@ static void draw_quad(int nump, Texture& colortex, int layer,
|
||||
if(!isfinite(w)) w = 0.0f;
|
||||
vec2 screen = (pos.sel(X, Y) * w + 1) * 0.5f *
|
||||
vec2_scalar(ctx->viewport.width(), ctx->viewport.height()) +
|
||||
vec2_scalar(ctx->viewport.x0, ctx->viewport.y0);
|
||||
make_vec2(ctx->viewport.origin() - colortex.offset);
|
||||
Point2D p[4] = {{screen.x.x, screen.y.x},
|
||||
{screen.x.y, screen.y.y},
|
||||
{screen.x.z, screen.y.z},
|
||||
@ -4166,6 +4196,7 @@ void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
|
||||
assert(depthtex.internal_format == GL_DEPTH_COMPONENT16);
|
||||
assert(colortex.width == depthtex.width &&
|
||||
colortex.height == depthtex.height);
|
||||
assert(colortex.offset == depthtex.offset);
|
||||
}
|
||||
|
||||
// debugf("current_vertex_array %d\n", ctx->current_vertex_array);
|
||||
|
@ -747,6 +747,8 @@ struct ivec2_scalar {
|
||||
return ivec2_scalar{select(c1), select(c2)};
|
||||
}
|
||||
|
||||
ivec2_scalar operator-() const { return ivec2_scalar{-x, -y}; }
|
||||
|
||||
ivec2_scalar& operator+=(ivec2_scalar a) {
|
||||
x += a.x;
|
||||
y += a.y;
|
||||
@ -771,6 +773,14 @@ struct ivec2_scalar {
|
||||
friend ivec2_scalar operator+(ivec2_scalar a, ivec2_scalar b) {
|
||||
return ivec2_scalar{a.x + b.x, a.y + b.y};
|
||||
}
|
||||
|
||||
friend ivec2_scalar operator-(ivec2_scalar a, ivec2_scalar b) {
|
||||
return ivec2_scalar{a.x - b.x, a.y - b.y};
|
||||
}
|
||||
|
||||
friend bool operator==(const ivec2_scalar& l, const ivec2_scalar& r) {
|
||||
return l.x == r.x && l.y == r.y;
|
||||
}
|
||||
};
|
||||
|
||||
struct ivec2 {
|
||||
|
@ -254,7 +254,14 @@ extern "C" {
|
||||
fn GetString(name: GLenum) -> *const c_char;
|
||||
fn GetStringi(name: GLenum, index: GLuint) -> *const c_char;
|
||||
fn GetError() -> GLenum;
|
||||
fn InitDefaultFramebuffer(width: i32, height: i32, stride: i32, buf: *mut c_void);
|
||||
fn InitDefaultFramebuffer(
|
||||
x: i32,
|
||||
y: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
stride: i32,
|
||||
buf: *mut c_void,
|
||||
);
|
||||
fn GetColorBuffer(
|
||||
fbo: GLuint,
|
||||
flush: GLboolean,
|
||||
@ -363,9 +370,17 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_default_framebuffer(&self, width: i32, height: i32, stride: i32, buf: *mut c_void) {
|
||||
pub fn init_default_framebuffer(
|
||||
&self,
|
||||
x: i32,
|
||||
y: i32,
|
||||
width: i32,
|
||||
height: i32,
|
||||
stride: i32,
|
||||
buf: *mut c_void,
|
||||
) {
|
||||
unsafe {
|
||||
InitDefaultFramebuffer(width, height, stride, buf);
|
||||
InitDefaultFramebuffer(x, y, width, height, stride, buf);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,7 +289,7 @@ impl WindowWrapper {
|
||||
#[cfg(feature = "software")]
|
||||
fn update_software(&self, dim: DeviceIntSize) {
|
||||
if let Some(swgl) = self.software_gl() {
|
||||
swgl.init_default_framebuffer(dim.width, dim.height, 0, std::ptr::null_mut());
|
||||
swgl.init_default_framebuffer(0, 0, dim.width, dim.height, 0, std::ptr::null_mut());
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user