зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1616715 - Make ReadPixelDesc per-call. r=lsalzman
GetSurfaceSnapshot (and similar) want to ReadPixels the backbuffer, without having to navigate the GL PIXEL_PACK state. Since this is cold cold code, it's nice to reduce the backend state by making ReadPixelsDesc/PixelPackState per-call, and tracked by the client. Arguably, PIXEL_PACK_BUFFER should be per-call as well. Differential Revision: https://phabricator.services.mozilla.com/D63587 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
011c0a1fd7
Коммит
1abd55a851
|
@ -895,16 +895,17 @@ already_AddRefed<gfx::SourceSurface> ClientWebGLContext::GetSurfaceSnapshot(
|
|||
|
||||
const auto drawFbWas = state.mBoundDrawFb;
|
||||
const auto readFbWas = state.mBoundReadFb;
|
||||
|
||||
const auto alignmentWas = Run<RPROC(GetParameter)>(LOCAL_GL_PACK_ALIGNMENT);
|
||||
if (!alignmentWas) return nullptr;
|
||||
const auto pboWas =
|
||||
Find(state.mBoundBufferByTarget, LOCAL_GL_PIXEL_PACK_BUFFER);
|
||||
|
||||
const auto size = DrawingBufferSize();
|
||||
|
||||
// -
|
||||
|
||||
BindFramebuffer(LOCAL_GL_FRAMEBUFFER, nullptr);
|
||||
PixelStorei(LOCAL_GL_PACK_ALIGNMENT, 4);
|
||||
if (pboWas) {
|
||||
BindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, nullptr);
|
||||
}
|
||||
|
||||
auto reset = MakeScopeExit([&] {
|
||||
if (drawFbWas == readFbWas) {
|
||||
|
@ -913,7 +914,9 @@ already_AddRefed<gfx::SourceSurface> ClientWebGLContext::GetSurfaceSnapshot(
|
|||
BindFramebuffer(LOCAL_GL_DRAW_FRAMEBUFFER, drawFbWas);
|
||||
BindFramebuffer(LOCAL_GL_READ_FRAMEBUFFER, readFbWas);
|
||||
}
|
||||
PixelStorei(LOCAL_GL_PACK_ALIGNMENT, *alignmentWas);
|
||||
if (pboWas) {
|
||||
BindBuffer(LOCAL_GL_PIXEL_PACK_BUFFER, pboWas);
|
||||
}
|
||||
});
|
||||
|
||||
const auto surfFormat = options.alpha ? gfx::SurfaceFormat::B8G8R8A8
|
||||
|
@ -934,10 +937,11 @@ already_AddRefed<gfx::SourceSurface> ClientWebGLContext::GetSurfaceSnapshot(
|
|||
}
|
||||
MOZ_ASSERT(static_cast<uint32_t>(map.GetStride()) == stride);
|
||||
|
||||
const auto desc = webgl::ReadPixelsDesc{{0, 0}, size};
|
||||
|
||||
const auto range = Range<uint8_t>(map.GetData(), stride * size.y);
|
||||
auto view = RawBufferView(range);
|
||||
Run<RPROC(ReadPixels)>(0, 0, size.x, size.y, LOCAL_GL_RGBA,
|
||||
LOCAL_GL_UNSIGNED_BYTE, view);
|
||||
Run<RPROC(ReadPixels)>(desc, view);
|
||||
|
||||
// -
|
||||
|
||||
|
@ -1695,6 +1699,10 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname,
|
|||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_PACK_ALIGNMENT:
|
||||
retval.set(JS::NumberValue(state.mPixelPackState.alignment));
|
||||
return;
|
||||
|
||||
// -
|
||||
// Array returns
|
||||
|
||||
|
@ -1827,6 +1835,16 @@ void ClientWebGLContext::GetParameter(JSContext* cx, GLenum pname,
|
|||
case LOCAL_GL_MAX_ARRAY_TEXTURE_LAYERS:
|
||||
retval.set(JS::NumberValue(limits.maxTexArrayLayers));
|
||||
return;
|
||||
|
||||
case LOCAL_GL_PACK_ROW_LENGTH:
|
||||
retval.set(JS::NumberValue(state.mPixelPackState.rowLength));
|
||||
return;
|
||||
case LOCAL_GL_PACK_SKIP_PIXELS:
|
||||
retval.set(JS::NumberValue(state.mPixelPackState.skipPixels));
|
||||
return;
|
||||
case LOCAL_GL_PACK_SKIP_ROWS:
|
||||
retval.set(JS::NumberValue(state.mPixelPackState.skipRows));
|
||||
return;
|
||||
} // switch pname
|
||||
} // if webgl2
|
||||
|
||||
|
@ -2410,7 +2428,50 @@ void ClientWebGLContext::LineWidth(GLfloat width) {
|
|||
Run<RPROC(LineWidth)>(width);
|
||||
}
|
||||
|
||||
void ClientWebGLContext::PixelStorei(GLenum pname, GLint param) {
|
||||
void ClientWebGLContext::PixelStorei(const GLenum pname, const GLint iparam) {
|
||||
const FuncScope funcScope(*this, "pixelStorei");
|
||||
if (IsContextLost()) return;
|
||||
if (!ValidateNonNegative("param", iparam)) return;
|
||||
const auto param = static_cast<uint32_t>(iparam);
|
||||
|
||||
auto& state = State();
|
||||
auto& packState = state.mPixelPackState;
|
||||
switch (pname) {
|
||||
case LOCAL_GL_PACK_ALIGNMENT:
|
||||
switch (param) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
EnqueueError(LOCAL_GL_INVALID_VALUE,
|
||||
"PACK_ALIGNMENT must be one of [1,2,4,8], was %i.",
|
||||
iparam);
|
||||
return;
|
||||
}
|
||||
packState.alignment = param;
|
||||
return;
|
||||
|
||||
case LOCAL_GL_PACK_ROW_LENGTH:
|
||||
if (!mIsWebGL2) break;
|
||||
packState.rowLength = param;
|
||||
return;
|
||||
|
||||
case LOCAL_GL_PACK_SKIP_PIXELS:
|
||||
if (!mIsWebGL2) break;
|
||||
packState.skipPixels = param;
|
||||
return;
|
||||
|
||||
case LOCAL_GL_PACK_SKIP_ROWS:
|
||||
if (!mIsWebGL2) break;
|
||||
packState.skipRows = param;
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Run<RPROC(PixelStorei)>(pname, param);
|
||||
}
|
||||
|
||||
|
@ -3841,9 +3902,16 @@ void ClientWebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
ErrorResult& out_error) const {
|
||||
const FuncScope funcScope(*this, "readPixels");
|
||||
if (!ReadPixels_SharedPrecheck(aCallerType, out_error)) return;
|
||||
const auto& state = State();
|
||||
if (!ValidateNonNegative("width", width)) return;
|
||||
if (!ValidateNonNegative("height", height)) return;
|
||||
if (!ValidateNonNegative("offset", offset)) return;
|
||||
Run<RPROC(ReadPixelsPbo)>(x, y, width, height, format, type,
|
||||
static_cast<uint64_t>(offset));
|
||||
|
||||
const auto desc = webgl::ReadPixelsDesc{{x, y},
|
||||
*uvec2::From(width, height),
|
||||
{format, type},
|
||||
state.mPixelPackState};
|
||||
Run<RPROC(ReadPixelsPbo)>(desc, static_cast<uint64_t>(offset));
|
||||
}
|
||||
|
||||
void ClientWebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
|
@ -3854,6 +3922,9 @@ void ClientWebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
ErrorResult& out_error) const {
|
||||
const FuncScope funcScope(*this, "readPixels");
|
||||
if (!ReadPixels_SharedPrecheck(aCallerType, out_error)) return;
|
||||
const auto& state = State();
|
||||
if (!ValidateNonNegative("width", width)) return;
|
||||
if (!ValidateNonNegative("height", height)) return;
|
||||
|
||||
////
|
||||
|
||||
|
@ -3882,9 +3953,14 @@ void ClientWebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
|||
LOCAL_GL_INVALID_VALUE, &bytes, &byteLen)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto desc = webgl::ReadPixelsDesc{{x, y},
|
||||
*uvec2::From(width, height),
|
||||
{format, type},
|
||||
state.mPixelPackState};
|
||||
const auto range = Range<uint8_t>(bytes, byteLen);
|
||||
auto view = RawBufferView(range);
|
||||
Run<RPROC(ReadPixels)>(x, y, width, height, format, type, view);
|
||||
Run<RPROC(ReadPixels)>(desc, view);
|
||||
}
|
||||
|
||||
bool ClientWebGLContext::ReadPixels_SharedPrecheck(
|
||||
|
|
|
@ -177,6 +177,7 @@ class ContextGenerationInfo final {
|
|||
std::array<float, 4> mClearColor = {{0, 0, 0, 0}};
|
||||
std::array<float, 4> mBlendColor = {{0, 0, 0, 0}};
|
||||
std::array<float, 2> mDepthRange = {{0, 1}};
|
||||
webgl::PixelPackState mPixelPackState;
|
||||
|
||||
std::vector<GLenum> mCompressedTextureFormats;
|
||||
|
||||
|
|
|
@ -409,7 +409,7 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
|
|||
mContext->LinkProgram(*obj);
|
||||
}
|
||||
|
||||
void PixelStorei(GLenum pname, GLint param) const {
|
||||
void PixelStorei(GLenum pname, uint32_t param) const {
|
||||
mContext->PixelStorei(pname, param);
|
||||
}
|
||||
|
||||
|
@ -646,15 +646,15 @@ class HostWebGLContext final : public SupportsWeakPtr<HostWebGLContext> {
|
|||
}
|
||||
|
||||
// ------------------------------ Readback -------------------------------
|
||||
void ReadPixelsPbo(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type, uint64_t offset) const {
|
||||
mContext->ReadPixelsPbo(x, y, width, height, format, type, offset);
|
||||
void ReadPixelsPbo(const webgl::ReadPixelsDesc& desc,
|
||||
const uint64_t offset) const {
|
||||
mContext->ReadPixelsPbo(desc, offset);
|
||||
}
|
||||
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type, RawBuffer<uint8_t>& dest) const {
|
||||
void ReadPixels(const webgl::ReadPixelsDesc& desc,
|
||||
RawBuffer<uint8_t>& dest) const {
|
||||
const auto range = MakeRange(dest);
|
||||
mContext->ReadPixels(x, y, width, height, format, type, range);
|
||||
mContext->ReadPixels(desc, range);
|
||||
}
|
||||
|
||||
// ----------------------------- Sampler -----------------------------------
|
||||
|
|
|
@ -610,7 +610,7 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
|
|||
|
||||
void LineWidth(GLfloat width);
|
||||
void LinkProgram(WebGLProgram& prog);
|
||||
void PixelStorei(GLenum pname, GLint param);
|
||||
void PixelStorei(GLenum pname, uint32_t param);
|
||||
void PolygonOffset(GLfloat factor, GLfloat units);
|
||||
|
||||
RefPtr<layers::SharedSurfaceTextureClient> GetVRFrame();
|
||||
|
@ -623,20 +623,15 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
|
|||
const webgl::FormatUsageInfo* usage) const;
|
||||
|
||||
protected:
|
||||
void ReadPixelsImpl(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type, uintptr_t data,
|
||||
void ReadPixelsImpl(const webgl::ReadPixelsDesc&, uintptr_t data,
|
||||
uint64_t dataLen);
|
||||
bool DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat, GLint x,
|
||||
GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum destType, uintptr_t dest,
|
||||
bool DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat,
|
||||
const webgl::ReadPixelsDesc&, uintptr_t dest,
|
||||
uint64_t dataLen, uint32_t rowStride);
|
||||
|
||||
public:
|
||||
void ReadPixelsPbo(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type, uint64_t offset);
|
||||
|
||||
void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type, const Range<uint8_t>& dest);
|
||||
void ReadPixelsPbo(const webgl::ReadPixelsDesc&, uint64_t offset);
|
||||
void ReadPixels(const webgl::ReadPixelsDesc&, const Range<uint8_t>& dest);
|
||||
|
||||
////
|
||||
|
||||
|
@ -1161,10 +1156,6 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr<WebGLContext> {
|
|||
CheckedUint32 GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height,
|
||||
uint32_t depth, uint8_t bytesPerPixel);
|
||||
|
||||
bool ValidatePackSize(uint32_t width, uint32_t height, uint8_t bytesPerPixel,
|
||||
uint32_t* const out_rowStride,
|
||||
uint32_t* const out_endOffset);
|
||||
|
||||
UniquePtr<webgl::TexUnpackBlob> FromDomElem(
|
||||
const dom::HTMLCanvasElement& canvas, TexImageTarget target, uvec3 size,
|
||||
const dom::Element& elem, ErrorResult* const out_error) const;
|
||||
|
|
|
@ -734,7 +734,7 @@ void WebGLContext::LinkProgram(WebGLProgram& prog) {
|
|||
}
|
||||
}
|
||||
|
||||
void WebGLContext::PixelStorei(GLenum pname, GLint param) {
|
||||
void WebGLContext::PixelStorei(GLenum pname, uint32_t param) {
|
||||
const FuncScope funcScope(*this, "pixelStorei");
|
||||
if (IsContextLost()) return;
|
||||
|
||||
|
@ -760,24 +760,10 @@ void WebGLContext::PixelStorei(GLenum pname, GLint param) {
|
|||
case LOCAL_GL_UNPACK_SKIP_PIXELS:
|
||||
pValueSlot = &mPixelStore.mUnpackSkipPixels;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_PACK_ROW_LENGTH:
|
||||
pValueSlot = &mPixelStore.mPackRowLength;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_PACK_SKIP_ROWS:
|
||||
pValueSlot = &mPixelStore.mPackSkipRows;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_PACK_SKIP_PIXELS:
|
||||
pValueSlot = &mPixelStore.mPackSkipPixels;
|
||||
break;
|
||||
}
|
||||
|
||||
if (pValueSlot) {
|
||||
if (!ValidateNonNegative("param", param)) return;
|
||||
|
||||
gl->fPixelStorei(pname, param);
|
||||
gl->fPixelStorei(pname, static_cast<int32_t>(param));
|
||||
*pValueSlot = param;
|
||||
return;
|
||||
}
|
||||
|
@ -811,19 +797,14 @@ void WebGLContext::PixelStorei(GLenum pname, GLint param) {
|
|||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_PACK_ALIGNMENT:
|
||||
case LOCAL_GL_UNPACK_ALIGNMENT:
|
||||
switch (param) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
if (pname == LOCAL_GL_PACK_ALIGNMENT)
|
||||
mPixelStore.mPackAlignment = param;
|
||||
else if (pname == LOCAL_GL_UNPACK_ALIGNMENT)
|
||||
mPixelStore.mUnpackAlignment = param;
|
||||
|
||||
gl->fPixelStorei(pname, param);
|
||||
mPixelStore.mUnpackAlignment = param;
|
||||
gl->fPixelStorei(pname, static_cast<int32_t>(param));
|
||||
return;
|
||||
|
||||
default:
|
||||
|
@ -839,30 +820,32 @@ void WebGLContext::PixelStorei(GLenum pname, GLint param) {
|
|||
return;
|
||||
}
|
||||
|
||||
bool WebGLContext::DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat,
|
||||
GLint x, GLint y, GLsizei width,
|
||||
GLsizei height, GLenum format,
|
||||
GLenum destType, uintptr_t dest,
|
||||
uint64_t destSize,
|
||||
uint32_t rowStride) {
|
||||
bool WebGLContext::DoReadPixelsAndConvert(
|
||||
const webgl::FormatInfo* const srcFormat, const webgl::ReadPixelsDesc& desc,
|
||||
const uintptr_t dest, const uint64_t destSize, const uint32_t rowStride) {
|
||||
const auto& x = desc.srcOffset.x;
|
||||
const auto& y = desc.srcOffset.y;
|
||||
const auto size = *ivec2::From(desc.size);
|
||||
const auto& pi = desc.pi;
|
||||
|
||||
// On at least Win+NV, we'll get PBO errors if we don't have at least
|
||||
// `rowStride * height` bytes available to read into.
|
||||
const auto naiveBytesNeeded = CheckedInt<uint64_t>(rowStride) * height;
|
||||
const auto naiveBytesNeeded = CheckedInt<uint64_t>(rowStride) * size.y;
|
||||
const bool isDangerCloseToEdge =
|
||||
(!naiveBytesNeeded.isValid() || naiveBytesNeeded.value() > destSize);
|
||||
const bool useParanoidHandling =
|
||||
(gl->WorkAroundDriverBugs() && isDangerCloseToEdge &&
|
||||
mBoundPixelPackBuffer);
|
||||
if (!useParanoidHandling) {
|
||||
gl->fReadPixels(x, y, width, height, format, destType,
|
||||
gl->fReadPixels(x, y, size.x, size.y, pi.format, pi.type,
|
||||
reinterpret_cast<void*>(dest));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Read everything but the last row.
|
||||
const auto bodyHeight = height - 1;
|
||||
const auto bodyHeight = size.y - 1;
|
||||
if (bodyHeight) {
|
||||
gl->fReadPixels(x, y, width, bodyHeight, format, destType,
|
||||
gl->fReadPixels(x, y, size.x, bodyHeight, pi.format, pi.type,
|
||||
reinterpret_cast<void*>(dest));
|
||||
}
|
||||
|
||||
|
@ -871,20 +854,33 @@ bool WebGLContext::DoReadPixelsAndConvert(const webgl::FormatInfo* srcFormat,
|
|||
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, 0);
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, 0);
|
||||
|
||||
const auto tailRowOffset = (char*)dest + rowStride * bodyHeight;
|
||||
gl->fReadPixels(x, y + bodyHeight, width, 1, format, destType, tailRowOffset);
|
||||
const auto tailRowOffset =
|
||||
reinterpret_cast<uint8_t*>(dest) + rowStride * bodyHeight;
|
||||
gl->fReadPixels(x, y + bodyHeight, size.x, 1, pi.format, pi.type,
|
||||
tailRowOffset);
|
||||
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, mPixelStore.mPackAlignment);
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore.mPackRowLength);
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore.mPackSkipRows);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebGLContext::ValidatePackSize(uint32_t width, uint32_t height,
|
||||
uint8_t bytesPerPixel,
|
||||
uint32_t* const out_rowStride,
|
||||
uint32_t* const out_endOffset) {
|
||||
if (!width || !height) {
|
||||
static bool ValidatePackSize(const WebGLContext& webgl,
|
||||
const webgl::PixelPackState& packing,
|
||||
const uvec2& size, uint8_t bytesPerPixel,
|
||||
uint32_t* const out_rowStride,
|
||||
uint32_t* const out_endOffset) {
|
||||
const auto alignment = packing.alignment;
|
||||
switch (alignment) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false);
|
||||
webgl.ErrorImplementationBug("Invalid PACK_ALIGNMENT.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!size.x || !size.y) {
|
||||
*out_rowStride = 0;
|
||||
*out_endOffset = 0;
|
||||
return true;
|
||||
|
@ -892,17 +888,15 @@ bool WebGLContext::ValidatePackSize(uint32_t width, uint32_t height,
|
|||
|
||||
// GLES 3.0.4, p116 (PACK_ functions like UNPACK_)
|
||||
|
||||
const auto rowLength =
|
||||
(mPixelStore.mPackRowLength ? mPixelStore.mPackRowLength : width);
|
||||
const auto skipPixels = mPixelStore.mPackSkipPixels;
|
||||
const auto skipRows = mPixelStore.mPackSkipRows;
|
||||
const auto alignment = mPixelStore.mPackAlignment;
|
||||
const auto rowLength = (packing.rowLength ? packing.rowLength : size.x);
|
||||
const auto skipPixels = packing.skipPixels;
|
||||
const auto skipRows = packing.skipRows;
|
||||
|
||||
const auto usedPixelsPerRow = CheckedUint32(skipPixels) + width;
|
||||
const auto usedRowsPerImage = CheckedUint32(skipRows) + height;
|
||||
const auto usedPixelsPerRow = CheckedUint32(skipPixels) + size.x;
|
||||
const auto usedRowsPerImage = CheckedUint32(skipRows) + size.y;
|
||||
|
||||
if (!usedPixelsPerRow.isValid() || usedPixelsPerRow.value() > rowLength) {
|
||||
ErrorInvalidOperation("SKIP_PIXELS + width > ROW_LENGTH.");
|
||||
webgl.ErrorInvalidOperation("SKIP_PIXELS + width > ROW_LENGTH.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -914,7 +908,7 @@ bool WebGLContext::ValidatePackSize(uint32_t width, uint32_t height,
|
|||
(usedRowsPerImage - 1) * rowStride + usedBytesPerRow;
|
||||
|
||||
if (!rowStride.isValid() || !usedBytesPerImage.isValid()) {
|
||||
ErrorInvalidOperation("Invalid UNPACK_ params.");
|
||||
webgl.ErrorInvalidOperation("Invalid UNPACK_ params.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -923,8 +917,7 @@ bool WebGLContext::ValidatePackSize(uint32_t width, uint32_t height,
|
|||
return true;
|
||||
}
|
||||
|
||||
void WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum format, GLenum type,
|
||||
void WebGLContext::ReadPixels(const webgl::ReadPixelsDesc& desc,
|
||||
const Range<uint8_t>& dest) {
|
||||
const FuncScope funcScope(*this, "readPixels");
|
||||
if (IsContextLost()) return;
|
||||
|
@ -934,14 +927,12 @@ void WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height,
|
|||
return;
|
||||
}
|
||||
|
||||
ReadPixelsImpl(x, y, width, height, format, type,
|
||||
reinterpret_cast<uintptr_t>(dest.begin().get()),
|
||||
ReadPixelsImpl(desc, reinterpret_cast<uintptr_t>(dest.begin().get()),
|
||||
dest.length());
|
||||
}
|
||||
|
||||
void WebGLContext::ReadPixelsPbo(GLint x, GLint y, GLsizei width,
|
||||
GLsizei height, GLenum format, GLenum type,
|
||||
uint64_t offset) {
|
||||
void WebGLContext::ReadPixelsPbo(const webgl::ReadPixelsDesc& desc,
|
||||
const uint64_t offset) {
|
||||
const FuncScope funcScope(*this, "readPixels");
|
||||
if (IsContextLost()) return;
|
||||
|
||||
|
@ -951,7 +942,8 @@ void WebGLContext::ReadPixelsPbo(GLint x, GLint y, GLsizei width,
|
|||
//////
|
||||
|
||||
{
|
||||
const auto bytesPerType = webgl::BytesPerPixel({LOCAL_GL_RED, type});
|
||||
const auto bytesPerType =
|
||||
webgl::BytesPerPixel({LOCAL_GL_RED, desc.pi.type});
|
||||
|
||||
if (offset % bytesPerType != 0) {
|
||||
ErrorInvalidOperation(
|
||||
|
@ -974,7 +966,7 @@ void WebGLContext::ReadPixelsPbo(GLint x, GLint y, GLsizei width,
|
|||
|
||||
const ScopedLazyBind lazyBind(gl, LOCAL_GL_PIXEL_PACK_BUFFER, buffer);
|
||||
|
||||
ReadPixelsImpl(x, y, width, height, format, type, offset, bytesAvailable);
|
||||
ReadPixelsImpl(desc, offset, bytesAvailable);
|
||||
|
||||
buffer->ResetLastUpdateFenceId();
|
||||
}
|
||||
|
@ -1082,20 +1074,9 @@ static bool ValidateReadPixelsFormatAndType(
|
|||
return false;
|
||||
}
|
||||
|
||||
void WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth,
|
||||
GLsizei rawHeight, GLenum packFormat,
|
||||
GLenum packType, uintptr_t dest,
|
||||
uint64_t availBytes) {
|
||||
if (!ValidateNonNegative("width", rawWidth) ||
|
||||
!ValidateNonNegative("height", rawHeight)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t width(rawWidth);
|
||||
const uint32_t height(rawHeight);
|
||||
|
||||
//////
|
||||
|
||||
void WebGLContext::ReadPixelsImpl(const webgl::ReadPixelsDesc& desc,
|
||||
const uintptr_t dest,
|
||||
const uint64_t availBytes) {
|
||||
const webgl::FormatUsageInfo* srcFormat;
|
||||
uint32_t srcWidth;
|
||||
uint32_t srcHeight;
|
||||
|
@ -1103,20 +1084,29 @@ void WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth,
|
|||
|
||||
//////
|
||||
|
||||
const webgl::PackingInfo pi = {packFormat, packType};
|
||||
if (!ValidateReadPixelsFormatAndType(srcFormat, pi, gl, this)) return;
|
||||
if (!ValidateReadPixelsFormatAndType(srcFormat, desc.pi, gl, this)) return;
|
||||
|
||||
uint8_t bytesPerPixel;
|
||||
if (!webgl::GetBytesPerPixel(pi, &bytesPerPixel)) {
|
||||
if (!webgl::GetBytesPerPixel(desc.pi, &bytesPerPixel)) {
|
||||
ErrorInvalidOperation("Unsupported format and type.");
|
||||
return;
|
||||
}
|
||||
|
||||
//////
|
||||
|
||||
const auto& srcOffset = desc.srcOffset;
|
||||
const auto& size = desc.size;
|
||||
|
||||
if (!ivec2::From(size)) {
|
||||
ErrorInvalidValue("width and height must be non-negative.");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& packing = desc.packState;
|
||||
uint32_t rowStride;
|
||||
uint32_t bytesNeeded;
|
||||
if (!ValidatePackSize(width, height, bytesPerPixel, &rowStride, &bytesNeeded))
|
||||
if (!ValidatePackSize(*this, packing, size, bytesPerPixel, &rowStride,
|
||||
&bytesNeeded))
|
||||
return;
|
||||
|
||||
if (bytesNeeded > availBytes) {
|
||||
|
@ -1129,8 +1119,8 @@ void WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth,
|
|||
int32_t readX, readY;
|
||||
int32_t writeX, writeY;
|
||||
int32_t rwWidth, rwHeight;
|
||||
if (!Intersect(srcWidth, x, width, &readX, &writeX, &rwWidth) ||
|
||||
!Intersect(srcHeight, y, height, &readY, &writeY, &rwHeight)) {
|
||||
if (!Intersect(srcWidth, srcOffset.x, size.x, &readX, &writeX, &rwWidth) ||
|
||||
!Intersect(srcHeight, srcOffset.y, size.y, &readY, &writeY, &rwHeight)) {
|
||||
ErrorOutOfMemory("Bad subrect selection.");
|
||||
return;
|
||||
}
|
||||
|
@ -1138,15 +1128,23 @@ void WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth,
|
|||
////////////////
|
||||
// Now that the errors are out of the way, on to actually reading!
|
||||
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, packing.alignment);
|
||||
if (IsWebGL2()) {
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, packing.rowLength);
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, packing.skipPixels);
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, packing.skipRows);
|
||||
}
|
||||
|
||||
if (!rwWidth || !rwHeight) {
|
||||
// Disjoint rects, so we're done already.
|
||||
DummyReadFramebufferOperation();
|
||||
return;
|
||||
}
|
||||
const auto rwSize = *uvec2::From(rwWidth, rwHeight);
|
||||
|
||||
if (uint32_t(rwWidth) == width && uint32_t(rwHeight) == height) {
|
||||
DoReadPixelsAndConvert(srcFormat->format, x, y, width, height, packFormat,
|
||||
packType, dest, bytesNeeded, rowStride);
|
||||
if (rwSize == size) {
|
||||
DoReadPixelsAndConvert(srcFormat->format, desc, dest, bytesNeeded,
|
||||
rowStride);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1166,29 +1164,31 @@ void WebGLContext::ReadPixelsImpl(GLint x, GLint y, GLsizei rawWidth,
|
|||
// Read only the in-bounds pixels.
|
||||
|
||||
if (IsWebGL2()) {
|
||||
if (!mPixelStore.mPackRowLength) {
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH,
|
||||
mPixelStore.mPackSkipPixels + width);
|
||||
if (!packing.rowLength) {
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, packing.skipPixels + size.x);
|
||||
}
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS,
|
||||
mPixelStore.mPackSkipPixels + writeX);
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS,
|
||||
mPixelStore.mPackSkipRows + writeY);
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, packing.skipPixels + writeX);
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, packing.skipRows + writeY);
|
||||
|
||||
DoReadPixelsAndConvert(srcFormat->format, readX, readY, rwWidth, rwHeight,
|
||||
packFormat, packType, dest, bytesNeeded, rowStride);
|
||||
auto desc2 = desc;
|
||||
desc2.srcOffset = {readX, readY};
|
||||
desc2.size = rwSize;
|
||||
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_ROW_LENGTH, mPixelStore.mPackRowLength);
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_PIXELS, mPixelStore.mPackSkipPixels);
|
||||
gl->fPixelStorei(LOCAL_GL_PACK_SKIP_ROWS, mPixelStore.mPackSkipRows);
|
||||
DoReadPixelsAndConvert(srcFormat->format, desc2, dest, bytesNeeded,
|
||||
rowStride);
|
||||
} else {
|
||||
// I *did* say "hilariously slow".
|
||||
|
||||
auto desc2 = desc;
|
||||
desc2.srcOffset = {readX, readY};
|
||||
desc2.size = {rwSize.x, 1};
|
||||
|
||||
auto row = dest + writeX * bytesPerPixel;
|
||||
row += writeY * rowStride;
|
||||
for (uint32_t j = 0; j < uint32_t(rwHeight); j++) {
|
||||
DoReadPixelsAndConvert(srcFormat->format, readX, readY + j, rwWidth, 1,
|
||||
packFormat, packType, row, bytesNeeded, rowStride);
|
||||
for (const auto j : IntegerRange(size.y)) {
|
||||
desc2.srcOffset.y = readY + j;
|
||||
DoReadPixelsAndConvert(srcFormat->format, desc2, row, bytesNeeded,
|
||||
rowStride);
|
||||
row += rowStride;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -546,8 +546,6 @@ void WebGLContext::AssertCachedGlobalState() const {
|
|||
MOZ_ASSERT(int4[0] == mViewportX && int4[1] == mViewportY &&
|
||||
int4[2] == mViewportWidth && int4[3] == mViewportHeight);
|
||||
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_PACK_ALIGNMENT,
|
||||
mPixelStore.mPackAlignment);
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT,
|
||||
mPixelStore.mUnpackAlignment);
|
||||
|
||||
|
@ -562,12 +560,6 @@ void WebGLContext::AssertCachedGlobalState() const {
|
|||
mPixelStore.mUnpackSkipRows);
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_PIXELS,
|
||||
mPixelStore.mUnpackSkipPixels);
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_PACK_ROW_LENGTH,
|
||||
mPixelStore.mPackRowLength);
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_ROWS,
|
||||
mPixelStore.mPackSkipRows);
|
||||
AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_PIXELS,
|
||||
mPixelStore.mPackSkipPixels);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!gl::GLContext::IsBadCallError(errorScope.GetError()));
|
||||
|
|
|
@ -589,10 +589,6 @@ bool WebGLContext::InitAndValidateGL(FailureReason* const out_failReason) {
|
|||
mPixelStore.mUnpackSkipRows = 0;
|
||||
mPixelStore.mUnpackSkipPixels = 0;
|
||||
mPixelStore.mUnpackAlignment = 4;
|
||||
mPixelStore.mPackRowLength = 0;
|
||||
mPixelStore.mPackSkipRows = 0;
|
||||
mPixelStore.mPackSkipPixels = 0;
|
||||
mPixelStore.mPackAlignment = 4;
|
||||
|
||||
mPrimRestartTypeBytes = 0;
|
||||
|
||||
|
|
|
@ -276,29 +276,6 @@ struct FormatInfo {
|
|||
}
|
||||
};
|
||||
|
||||
struct PackingInfo {
|
||||
GLenum format;
|
||||
GLenum type;
|
||||
|
||||
bool operator<(const PackingInfo& x) const {
|
||||
if (format != x.format) return format < x.format;
|
||||
|
||||
return type < x.type;
|
||||
}
|
||||
|
||||
bool operator==(const PackingInfo& x) const {
|
||||
return (format == x.format && type == x.type);
|
||||
}
|
||||
};
|
||||
|
||||
struct DriverUnpackInfo {
|
||||
GLenum internalFormat;
|
||||
GLenum unpackFormat;
|
||||
GLenum unpackType;
|
||||
|
||||
PackingInfo ToPacking() const { return {unpackFormat, unpackType}; }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const FormatInfo* GetFormat(EffectiveFormat format);
|
||||
|
|
|
@ -349,17 +349,13 @@ struct FloatOrInt final // For TexParameter[fi] and friends.
|
|||
}
|
||||
};
|
||||
|
||||
struct WebGLPixelStore {
|
||||
struct WebGLPixelStore final {
|
||||
uint32_t mUnpackImageHeight = 0;
|
||||
uint32_t mUnpackSkipImages = 0;
|
||||
uint32_t mUnpackRowLength = 0;
|
||||
uint32_t mUnpackSkipRows = 0;
|
||||
uint32_t mUnpackSkipPixels = 0;
|
||||
uint32_t mUnpackAlignment = 0;
|
||||
uint32_t mPackRowLength = 0;
|
||||
uint32_t mPackSkipRows = 0;
|
||||
uint32_t mPackSkipPixels = 0;
|
||||
uint32_t mPackAlignment = 0;
|
||||
GLenum mColorspaceConversion = 0;
|
||||
bool mFlipY = false;
|
||||
bool mPremultiplyAlpha = false;
|
||||
|
@ -465,6 +461,43 @@ typedef avec3<uint32_t> uvec3;
|
|||
|
||||
namespace webgl {
|
||||
|
||||
struct PackingInfo final {
|
||||
GLenum format = 0;
|
||||
GLenum type = 0;
|
||||
|
||||
bool operator<(const PackingInfo& x) const {
|
||||
if (format != x.format) return format < x.format;
|
||||
|
||||
return type < x.type;
|
||||
}
|
||||
|
||||
bool operator==(const PackingInfo& x) const {
|
||||
return (format == x.format && type == x.type);
|
||||
}
|
||||
};
|
||||
|
||||
struct DriverUnpackInfo final {
|
||||
GLenum internalFormat = 0;
|
||||
GLenum unpackFormat = 0;
|
||||
GLenum unpackType = 0;
|
||||
|
||||
PackingInfo ToPacking() const { return {unpackFormat, unpackType}; }
|
||||
};
|
||||
|
||||
struct PixelPackState final {
|
||||
uint32_t alignment = 4;
|
||||
uint32_t rowLength = 0;
|
||||
uint32_t skipRows = 0;
|
||||
uint32_t skipPixels = 0;
|
||||
};
|
||||
|
||||
struct ReadPixelsDesc final {
|
||||
ivec2 srcOffset;
|
||||
uvec2 size;
|
||||
PackingInfo pi = {LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE};
|
||||
PixelPackState packState;
|
||||
};
|
||||
|
||||
class ExtensionBits final {
|
||||
uint64_t mBits = 0;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче