Bug 1640607 - Send SurfaceDescriptors for GPU blitting for video-to-webgl. r=lsalzman

Differential Revision: https://phabricator.services.mozilla.com/D101061
This commit is contained in:
Jeff Gilbert 2021-01-14 01:23:06 +00:00
parent 4dd35ffb42
commit a8926ffa47
20 changed files with 400 additions and 225 deletions

View File

@ -3882,7 +3882,6 @@ webgl::TexUnpackBlobDesc FromImageData(GLenum target, uvec3 size,
Maybe<webgl::TexUnpackBlobDesc> FromDomElem(const ClientWebGLContext&,
GLenum target, uvec3 size,
const dom::Element& src,
const bool allowBlitImage,
ErrorResult* const out_error);
} // namespace webgl
@ -3995,17 +3994,8 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
}
if (src.mDomElem) {
bool canUseLayerImage = true;
if (StaticPrefs::webgl_disable_DOM_blit_uploads()) {
canUseLayerImage = false;
}
if (mNotLost && mNotLost->outOfProcess) {
canUseLayerImage = false;
}
return webgl::FromDomElem(*this, imageTarget, explicitSize,
*(src.mDomElem), canUseLayerImage,
src.mOut_error);
*(src.mDomElem), src.mOut_error);
}
return Some(webgl::TexUnpackBlobDesc{
@ -4021,20 +4011,17 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
// UNPACK_ALIGNMENT are not strictly defined. These restrictions ensure
// consistent and efficient behavior regardless of implied UNPACK_ params.
Maybe<gfx::IntSize> structuredSrcSize;
if (desc->surf) {
structuredSrcSize = Some(desc->surf->GetSize());
}
if (desc->image) {
structuredSrcSize = Some(desc->image->GetSize());
Maybe<uvec2> structuredSrcSize;
if (desc->dataSurf || desc->sd) {
structuredSrcSize = Some(desc->imageSize);
}
if (structuredSrcSize) {
auto& size = desc->size;
if (!size.x) {
size.x = structuredSrcSize->width;
size.x = structuredSrcSize->x;
}
if (!size.y) {
size.y = structuredSrcSize->height;
size.y = structuredSrcSize->x;
}
}
@ -4057,7 +4044,50 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
// -
if (desc->sd) {
auto fallbackReason = BlitPreventReason(level, offset, pi, *desc);
const auto& sd = *(desc->sd);
const auto sdType = sd.type();
const auto& contextInfo = mNotLost->info;
const bool canUploadViaSd = contextInfo.uploadableSdTypes[sdType];
if (!canUploadViaSd) {
const nsPrintfCString msg(
"Fast uploads for resource type %i not implemented.", int(sdType));
fallbackReason.reset();
fallbackReason.emplace(ToString(msg));
}
if (StaticPrefs::webgl_disable_DOM_blit_uploads()) {
fallbackReason.reset();
fallbackReason.emplace("DOM blit uploads are disabled.");
}
if (fallbackReason) {
EnqueuePerfWarning("Missed GPU-copy fast-path: %s",
fallbackReason->c_str());
const auto& image = desc->image;
const RefPtr<gfx::SourceSurface> surf = image->GetAsSourceSurface();
if (surf) {
// WARNING: OSX can lose our MakeCurrent here.
desc->dataSurf = surf->GetDataSurface();
}
if (!desc->dataSurf) {
EnqueueError(LOCAL_GL_OUT_OF_MEMORY,
"Failed to retrieve source bytes for CPU upload.");
return;
}
desc->sd = Nothing();
}
}
desc->image = nullptr;
// -
desc->Shrink(pi);
Run<RPROC(TexImage)>(static_cast<uint32_t>(level), respecFormat,
CastUvec3(offset), pi, std::move(*desc));
scopedArr.Reset(); // (For the hazard analysis) Done with the data.

View File

@ -877,6 +877,11 @@ class ClientWebGLContext final : public nsICanvasRenderingContextInternal,
EnqueueError(0, format, args...);
}
template <typename... Args>
void EnqueuePerfWarning(const char* const format, const Args&... args) const {
EnqueueError(webgl::kErrorPerfWarning, format, args...);
}
void EnqueueError_ArgEnum(const char* argName,
GLenum val) const; // Cold code.

View File

@ -398,24 +398,25 @@ struct QueueParamTraits<webgl::TexUnpackBlobDesc> {
template <typename U>
static QueueStatus Write(ProducerView<U>& view, const ParamType& in) {
MOZ_ASSERT(!in.image);
const bool isSurf = bool(in.surf);
MOZ_RELEASE_ASSERT(!in.image);
const bool isDataSurf = bool(in.dataSurf);
if (!view.WriteParam(in.imageTarget) || !view.WriteParam(in.size) ||
!view.WriteParam(in.srcAlphaType) || !view.WriteParam(in.unpacking) ||
!view.WriteParam(in.cpuData) || !view.WriteParam(in.pboOffset) ||
!view.WriteParam(isSurf)) {
!view.WriteParam(in.imageSize) || !view.WriteParam(in.sd) ||
!view.WriteParam(isDataSurf)) {
return view.GetStatus();
}
if (isSurf) {
gfx::DataSourceSurface::ScopedMap map(in.surf,
gfx::DataSourceSurface::READ);
if (isDataSurf) {
const auto& surf = in.dataSurf;
gfx::DataSourceSurface::ScopedMap map(surf, gfx::DataSourceSurface::READ);
if (!map.IsMapped()) {
return QueueStatus::kOOMError;
}
const auto& surfSize = in.surf->GetSize();
const auto& surfSize = surf->GetSize();
const auto stride = *MaybeAs<size_t>(map.GetStride());
if (!view.WriteParam(surfSize) ||
!view.WriteParam(in.surf->GetFormat()) || !view.WriteParam(stride)) {
if (!view.WriteParam(surfSize) || !view.WriteParam(surf->GetFormat()) ||
!view.WriteParam(stride)) {
return view.GetStatus();
}
@ -430,14 +431,15 @@ struct QueueParamTraits<webgl::TexUnpackBlobDesc> {
template <typename U>
static QueueStatus Read(ConsumerView<U>& view, ParamType* const out) {
bool isSurf;
bool isDataSurf;
if (!view.ReadParam(&out->imageTarget) || !view.ReadParam(&out->size) ||
!view.ReadParam(&out->srcAlphaType) ||
!view.ReadParam(&out->unpacking) || !view.ReadParam(&out->cpuData) ||
!view.ReadParam(&out->pboOffset) || !view.ReadParam(&isSurf)) {
!view.ReadParam(&out->pboOffset) || !view.ReadParam(&out->imageSize) ||
!view.ReadParam(&out->sd) || !view.ReadParam(&isDataSurf)) {
return view.GetStatus();
}
if (isSurf) {
if (isDataSurf) {
gfx::IntSize surfSize;
gfx::SurfaceFormat format;
size_t stride;
@ -445,13 +447,14 @@ struct QueueParamTraits<webgl::TexUnpackBlobDesc> {
!view.ReadParam(&stride)) {
return view.GetStatus();
}
out->surf = gfx::Factory::CreateDataSourceSurfaceWithStride(
surfSize, format, stride, true);
if (!out->surf) {
auto& surf = out->dataSurf;
surf = gfx::Factory::CreateDataSourceSurfaceWithStride(surfSize, format,
stride, true);
if (!surf) {
return QueueStatus::kOOMError;
}
gfx::DataSourceSurface::ScopedMap map(out->surf,
gfx::DataSourceSurface::ScopedMap map(surf,
gfx::DataSourceSurface::WRITE);
if (!map.IsMapped()) {
return QueueStatus::kOOMError;

View File

@ -358,10 +358,10 @@ std::unique_ptr<TexUnpackBlob> TexUnpackBlob::Create(
return nullptr;
}
if (desc.image) {
if (desc.sd) {
return new TexUnpackImage(desc);
}
if (desc.surf) {
if (desc.dataSurf) {
return new TexUnpackSurface(desc);
}
@ -675,10 +675,59 @@ bool TexUnpackImage::Validate(const WebGLContext* const webgl,
const webgl::PackingInfo& pi) {
if (!ValidatePIForDOM(webgl, pi)) return false;
const auto fullRows = mDesc.image->GetSize().height;
const auto fullRows = mDesc.imageSize.y;
return ValidateUnpackPixels(webgl, fullRows, 0, this);
}
Maybe<std::string> BlitPreventReason(const int32_t level, const ivec3& offset,
const webgl::PackingInfo& pi,
const TexUnpackBlobDesc& desc) {
const auto& size = desc.size;
const auto& unpacking = desc.unpacking;
const auto ret = [&]() -> const char* {
if (size.z != 1) {
return "depth is not 1";
}
if (offset.x != 0 || offset.y != 0 || offset.z != 0) {
return "x/y/zOffset is not 0";
}
if (unpacking.mUnpackSkipPixels || unpacking.mUnpackSkipRows ||
unpacking.mUnpackSkipImages) {
return "non-zero UNPACK_SKIP_* not yet supported";
}
const auto premultReason = [&]() -> const char* {
if (desc.srcAlphaType == gfxAlphaType::Opaque) return nullptr;
const bool srcIsPremult = (desc.srcAlphaType == gfxAlphaType::Premult);
const auto& dstIsPremult = unpacking.mPremultiplyAlpha;
if (srcIsPremult == dstIsPremult) return nullptr;
if (dstIsPremult) {
return "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not true";
} else {
return "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not false";
}
}();
if (premultReason) return premultReason;
if (pi.format != LOCAL_GL_RGBA) {
return "`format` is not RGBA";
}
if (pi.type != LOCAL_GL_UNSIGNED_BYTE) {
return "`type` is not UNSIGNED_BYTE";
}
return nullptr;
}();
if (ret) {
return Some(std::string(ret));
}
return {};
}
bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
WebGLTexture* tex, GLint level,
const webgl::DriverUnpackInfo* dui,
@ -690,11 +739,25 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
const auto& webgl = tex->mContext;
const auto& target = mDesc.imageTarget;
const auto& size = mDesc.size;
const auto& image = mDesc.image;
const auto& sd = *(mDesc.sd);
const auto& unpacking = mDesc.unpacking;
const auto& gl = webgl->GL();
// -
const auto reason =
BlitPreventReason(level, {xOffset, yOffset, zOffset}, pi, mDesc);
if (reason) {
webgl->GeneratePerfWarning(
"Failed to hit GPU-copy fast-path."
" (%s) Falling back to CPU upload.",
reason->c_str());
return false;
}
// -
if (needsRespec) {
*out_error =
DoTexOrSubImage(isSubImage, gl, target, level, dui, xOffset, yOffset,
@ -702,50 +765,7 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
if (*out_error) return true;
}
const char* fallbackReason;
do {
if (size.z != 1) {
fallbackReason = "depth is not 1";
break;
}
if (xOffset != 0 || yOffset != 0 || zOffset != 0) {
fallbackReason = "x/y/zOffset is not 0";
break;
}
if (unpacking.mUnpackSkipPixels || unpacking.mUnpackSkipRows ||
unpacking.mUnpackSkipImages) {
fallbackReason = "non-zero UNPACK_SKIP_* not yet supported";
break;
}
const auto fnHasPremultMismatch = [&]() {
if (mDesc.srcAlphaType == gfxAlphaType::Opaque) return false;
const bool srcIsPremult = (mDesc.srcAlphaType == gfxAlphaType::Premult);
const auto& dstIsPremult = unpacking.mPremultiplyAlpha;
if (srcIsPremult == dstIsPremult) return false;
if (dstIsPremult) {
fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not true";
} else {
fallbackReason = "UNPACK_PREMULTIPLY_ALPHA_WEBGL is not false";
}
return true;
};
if (fnHasPremultMismatch()) break;
if (dui->unpackFormat != LOCAL_GL_RGB &&
dui->unpackFormat != LOCAL_GL_RGBA) {
fallbackReason = "`format` is not RGB or RGBA";
break;
}
if (dui->unpackType != LOCAL_GL_UNSIGNED_BYTE) {
fallbackReason = "`type` is not UNSIGNED_BYTE";
break;
}
{
gl::ScopedFramebuffer scopedFB(gl);
gl::ScopedBindFramebuffer bindFB(gl, scopedFB.FB());
@ -756,62 +776,24 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
LOCAL_GL_COLOR_ATTACHMENT0, target,
tex->mGLName, level);
if (errorScope.GetError()) {
fallbackReason = "bug: failed to attach to FB for blit";
break;
}
const auto err = errorScope.GetError();
MOZ_ALWAYS_TRUE(!err);
}
const GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
fallbackReason = "bug: failed to confirm FB for blit";
break;
}
MOZ_ALWAYS_TRUE(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
const auto dstOrigin =
(unpacking.mFlipY ? gl::OriginPos::TopLeft : gl::OriginPos::BottomLeft);
if (!gl->BlitHelper()->BlitImageToFramebuffer(image, {size.x, size.y},
dstOrigin)) {
fallbackReason = "likely bug: failed to blit";
break;
if (!gl->BlitHelper()->BlitSdToFramebuffer(sd, {size.x, size.y},
dstOrigin)) {
webgl->ErrorImplementationBug("BlitSdToFramebuffer failed for type %i.",
int(sd.type()));
return false;
}
// Blitting was successful, so we're done!
*out_error = 0;
return true;
} while (false);
const nsPrintfCString perfMsg(
"Failed to hit GPU-copy fast-path: %s (src type %u)", fallbackReason,
uint32_t(image->GetFormat()));
if (unpacking.mRequireFastPath) {
webgl->ErrorInvalidOperation("%s", perfMsg.BeginReading());
return false;
}
webgl->GeneratePerfWarning("%s Falling back to CPU upload.",
perfMsg.BeginReading());
const RefPtr<gfx::SourceSurface> surf = image->GetAsSourceSurface();
RefPtr<gfx::DataSourceSurface> dataSurf;
if (surf) {
// WARNING: OSX can lose our MakeCurrent here.
dataSurf = surf->GetDataSurface();
}
if (!dataSurf) {
webgl->ErrorOutOfMemory(
"GetAsSourceSurface or GetDataSurface failed after"
" blit failed for TexUnpackImage.");
return false;
}
const TexUnpackBlobDesc newDesc = {
target, size, mDesc.srcAlphaType, {}, {}, {}, dataSurf, unpacking};
const TexUnpackSurface surfBlob(newDesc);
return surfBlob.TexOrSubImage(isSubImage, needsRespec, tex, level, dui,
xOffset, yOffset, zOffset, pi, out_error);
return true;
}
////////////////////////////////////////////////////////////////////////////////
@ -875,7 +857,7 @@ bool TexUnpackSurface::Validate(const WebGLContext* const webgl,
const webgl::PackingInfo& pi) {
if (!ValidatePIForDOM(webgl, pi)) return false;
const auto fullRows = mDesc.surf->GetSize().height;
const auto fullRows = mDesc.dataSurf->GetSize().height;
return ValidateUnpackPixels(webgl, fullRows, 0, this);
}
@ -888,7 +870,7 @@ bool TexUnpackSurface::TexOrSubImage(bool isSubImage, bool needsRespec,
GLenum* const out_error) const {
const auto& webgl = tex->mContext;
const auto& size = mDesc.size;
auto& surf = *(mDesc.surf);
auto& surf = *(mDesc.dataSurf);
////

View File

@ -41,6 +41,10 @@ namespace webgl {
struct PackingInfo;
struct DriverUnpackInfo;
Maybe<std::string> BlitPreventReason(int32_t level, const ivec3& offset,
const webgl::PackingInfo&,
const TexUnpackBlobDesc&);
class TexUnpackBlob {
public:
const TexUnpackBlobDesc& mDesc;

View File

@ -588,8 +588,25 @@ RefPtr<WebGLContext> WebGLContext::Create(HostWebGLContext& host,
printf_stderr("--- WebGL context created: %p\n", webgl.get());
}
// -
const auto UploadableSdTypes = [&]() {
webgl::EnumMask<layers::SurfaceDescriptor::Type> types;
if (webgl->gl->IsANGLE()) {
types[layers::SurfaceDescriptor::TSurfaceDescriptorD3D10] = true;
types[layers::SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr] = true;
}
if (kIsMacOS) {
types[layers::SurfaceDescriptor::TSurfaceDescriptorMacIOSurface] = true;
}
return types;
};
// -
out->options = webgl->mOptions;
out->limits = *webgl->mLimits;
out->uploadableSdTypes = UploadableSdTypes();
return webgl;
}
@ -1398,8 +1415,8 @@ const char* WebGLContext::FuncName() const {
if (MOZ_LIKELY(mFuncScope)) {
ret = mFuncScope->mFuncName;
} else {
MOZ_ASSERT(false, "FuncScope not on stack!");
ret = "<funcName unknown>";
NS_WARNING("FuncScope not on stack!");
ret = "<unknown function>";
}
return ret;
}
@ -1504,12 +1521,20 @@ nsresult webgl::AvailabilityRunnable::Run() {
// -
void WebGLContext::GenerateErrorImpl(const GLenum err,
void WebGLContext::GenerateErrorImpl(const GLenum errOrWarning,
const std::string& text) const {
if (mFuncScope && mFuncScope->mBindFailureGuard) {
auto err = errOrWarning;
bool isPerfWarning = false;
if (err == webgl::kErrorPerfWarning) {
err = 0;
isPerfWarning = true;
}
if (err && mFuncScope && mFuncScope->mBindFailureGuard) {
gfxCriticalError() << "mBindFailureGuard failure: Generating error "
<< EnumString(err) << ": " << text;
}
/* ES2 section 2.5 "GL Errors" states that implementations can have
* multiple 'flags', as errors might be caught in different parts of
* a distributed implementation.
@ -1520,18 +1545,39 @@ void WebGLContext::GenerateErrorImpl(const GLenum err,
if (!mHost) return; // Impossible?
if (!ShouldGenerateWarnings()) return;
// -
mHost->JsWarning(text);
mWarningCount += 1;
const auto ShouldWarn = [&]() {
if (isPerfWarning) {
return ShouldGeneratePerfWarnings();
}
return ShouldGenerateWarnings();
};
if (!ShouldWarn()) return;
if (!ShouldGenerateWarnings()) {
auto info = std::string(
"WebGL: No further warnings will be reported for this WebGL "
"context. (already reported ");
info += std::to_string(mWarningCount);
info += " warnings)";
mHost->JsWarning(info);
// -
auto* pNumWarnings = &mWarningCount;
const char* warningsType = "warnings";
if (isPerfWarning) {
pNumWarnings = &mNumPerfWarnings;
warningsType = "perf warnings";
}
if (isPerfWarning) {
const auto perfText = std::string("WebGL perf warning: ") + text;
mHost->JsWarning(perfText);
} else {
mHost->JsWarning(text);
}
*pNumWarnings += 1;
if (!ShouldWarn()) {
const auto& msg = nsPrintfCString(
"After reporting %i, no further %s will be reported for this WebGL "
"context.",
int(*pNumWarnings), warningsType);
mHost->JsWarning(ToString(msg));
}
}

View File

@ -1237,35 +1237,7 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr {
template <typename... Args>
void GeneratePerfWarning(const char* const fmt, const Args&... args) const {
if (!ShouldGeneratePerfWarnings()) return;
const auto funcName = FuncName();
nsCString msg;
msg.AppendPrintf("WebGL perf warning: %s: ", funcName);
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wformat-security"
#elif defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-security"
#endif
msg.AppendPrintf(fmt, args...);
#ifdef __clang__
# pragma clang diagnostic pop
#elif defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
GenerateErrorImpl(0, msg);
mNumPerfWarnings++;
if (!ShouldGeneratePerfWarnings()) {
GenerateWarning(
"After reporting %u, no further WebGL perf warnings will"
" be reported for this WebGL context.",
uint32_t(mNumPerfWarnings));
}
GenerateError(webgl::kErrorPerfWarning, fmt, args...);
}
public:

View File

@ -226,6 +226,10 @@ struct ParamTraits<mozilla::webgl::OpaqueFramebufferOptions> final
// -
template <typename T>
struct ParamTraits<mozilla::webgl::EnumMask<T>> final
: public PlainOldDataSerializer<mozilla::webgl::EnumMask<T>> {};
template <>
struct ParamTraits<mozilla::webgl::InitContextResult> final {
using T = mozilla::webgl::InitContextResult;
@ -234,13 +238,15 @@ struct ParamTraits<mozilla::webgl::InitContextResult> final {
WriteParam(msg, in.error);
WriteParam(msg, in.options);
WriteParam(msg, in.limits);
WriteParam(msg, in.uploadableSdTypes);
}
static bool Read(const Message* const msg, PickleIterator* const itr,
T* const out) {
return ReadParam(msg, itr, &out->error) &&
ReadParam(msg, itr, &out->options) &&
ReadParam(msg, itr, &out->limits);
ReadParam(msg, itr, &out->limits) &&
ReadParam(msg, itr, &out->uploadableSdTypes);
}
};

View File

@ -68,6 +68,8 @@ struct IsTriviallySerializable<webgl::VertAttribPointerDesc> : std::true_type {
};
template <>
struct IsTriviallySerializable<webgl::ReadPixelsDesc> : std::true_type {};
template <>
struct IsTriviallySerializable<layers::SurfaceDescriptor> : std::true_type {};
template <typename T>
struct QueueParamTraits<RawBuffer<T>> {

View File

@ -50,20 +50,28 @@ Maybe<TexUnpackBlobDesc> FromImageBitmap(const GLenum target, uvec3 size,
}
const RefPtr<gfx::DataSourceSurface> surf = cloneData->mSurface;
const auto imageSize = *uvec2::FromSize(surf->GetSize());
if (!size.x) {
size.x = surf->GetSize().width;
size.x = imageSize.x;
}
if (!size.y) {
size.y = surf->GetSize().height;
size.y = imageSize.y;
}
// WhatWG "HTML Living Standard" (30 October 2015):
// "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
// non-premultiplied alpha values."
return Some(
TexUnpackBlobDesc{target, size, cloneData->mAlphaType, {}, {}, {}, surf});
return Some(TexUnpackBlobDesc{target,
size,
cloneData->mAlphaType,
{},
{},
imageSize,
nullptr,
{},
surf});
}
TexUnpackBlobDesc FromImageData(const GLenum target, uvec3 size,
@ -74,24 +82,25 @@ TexUnpackBlobDesc FromImageData(const GLenum target, uvec3 size,
const size_t dataSize = scopedArr->Length();
const auto data = reinterpret_cast<uint8_t*>(scopedArr->Data());
const gfx::IntSize imageSize(imageData.Width(), imageData.Height());
const size_t stride = imageSize.width * 4;
const gfx::IntSize imageISize(imageData.Width(), imageData.Height());
const auto imageUSize = *uvec2::FromSize(imageISize);
const size_t stride = imageUSize.x * 4;
const gfx::SurfaceFormat surfFormat = gfx::SurfaceFormat::R8G8B8A8;
MOZ_ALWAYS_TRUE(dataSize == stride * imageSize.height);
MOZ_ALWAYS_TRUE(dataSize == stride * imageUSize.y);
const RefPtr<gfx::DataSourceSurface> surf =
gfx::Factory::CreateWrappingDataSourceSurface(data, stride, imageSize,
gfx::Factory::CreateWrappingDataSourceSurface(data, stride, imageISize,
surfFormat);
MOZ_ASSERT(surf);
////
if (!size.x) {
size.x = imageData.Width();
size.x = imageUSize.x;
}
if (!size.y) {
size.y = imageData.Height();
size.y = imageUSize.y;
}
////
@ -99,13 +108,46 @@ TexUnpackBlobDesc FromImageData(const GLenum target, uvec3 size,
// WhatWG "HTML Living Standard" (30 October 2015):
// "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
// non-premultiplied alpha values."
return {target, size, gfxAlphaType::NonPremult, {}, {}, {}, surf};
return {target, size, gfxAlphaType::NonPremult, {}, {}, imageUSize, nullptr,
{}, surf};
}
static layers::SurfaceDescriptor Flatten(const layers::SurfaceDescriptor& sd) {
const auto sdType = sd.type();
if (sdType != layers::SurfaceDescriptor::TSurfaceDescriptorGPUVideo) {
return sd;
}
const auto& sdv = sd.get_SurfaceDescriptorGPUVideo();
const auto& sdvType = sdv.type();
if (sdvType !=
layers::SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder) {
return sd;
}
const auto& sdrd = sdv.get_SurfaceDescriptorRemoteDecoder();
const auto& subdesc = sdrd.subdesc();
const auto& subdescType = subdesc.type();
switch (subdescType) {
case layers::RemoteDecoderVideoSubDescriptor::T__None:
case layers::RemoteDecoderVideoSubDescriptor::Tnull_t:
return sd;
case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorD3D10:
return subdesc.get_SurfaceDescriptorD3D10();
case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorDXGIYCbCr:
return subdesc.get_SurfaceDescriptorDXGIYCbCr();
case layers::RemoteDecoderVideoSubDescriptor::TSurfaceDescriptorDMABuf:
return subdesc.get_SurfaceDescriptorDMABuf();
case layers::RemoteDecoderVideoSubDescriptor::
TSurfaceDescriptorMacIOSurface:
return subdesc.get_SurfaceDescriptorMacIOSurface();
}
MOZ_CRASH("unreachable");
}
Maybe<webgl::TexUnpackBlobDesc> FromDomElem(const ClientWebGLContext& webgl,
const GLenum target, uvec3 size,
const dom::Element& elem,
const bool allowBlitImage,
ErrorResult* const out_error) {
const auto& canvas = *webgl.GetCanvas();
@ -136,21 +178,23 @@ Maybe<webgl::TexUnpackBlobDesc> FromDomElem(const ClientWebGLContext& webgl,
//////
uint32_t elemWidth = 0;
uint32_t elemHeight = 0;
layers::Image* layersImage = nullptr;
uvec2 elemSize;
if (sfer.mLayersImage && allowBlitImage) {
layersImage = sfer.mLayersImage;
elemWidth = layersImage->GetSize().width;
elemHeight = layersImage->GetSize().height;
const auto& layersImage = sfer.mLayersImage;
Maybe<layers::SurfaceDescriptor> sd;
if (layersImage) {
elemSize = *uvec2::FromSize(layersImage->GetSize());
sd = layersImage->GetDesc();
if (sd) {
sd = Some(Flatten(*sd));
}
}
RefPtr<gfx::DataSourceSurface> dataSurf;
if (!layersImage && sfer.GetSourceSurface()) {
if (!sd && sfer.GetSourceSurface()) {
const auto surf = sfer.GetSourceSurface();
elemWidth = surf->GetSize().width;
elemHeight = surf->GetSize().height;
elemSize = *uvec2::FromSize(surf->GetSize());
// WARNING: OSX can lose our MakeCurrent here.
dataSurf = surf->GetDataSurface();
@ -159,16 +203,17 @@ Maybe<webgl::TexUnpackBlobDesc> FromDomElem(const ClientWebGLContext& webgl,
//////
if (!size.x) {
size.x = elemWidth;
size.x = elemSize.x;
}
if (!size.y) {
size.y = elemHeight;
size.y = elemSize.y;
}
////
if (!layersImage && !dataSurf) {
webgl.EnqueueWarning("Resource has no data (yet?). Uploading zeros.");
return Some(TexUnpackBlobDesc{target, size, gfxAlphaType::NonPremult});
}
@ -201,14 +246,15 @@ Maybe<webgl::TexUnpackBlobDesc> FromDomElem(const ClientWebGLContext& webgl,
//////
// Ok, we're good!
if (layersImage) {
return Some(
TexUnpackBlobDesc{target, size, sfer.mAlphaType, {}, {}, layersImage});
}
MOZ_ASSERT(dataSurf);
return Some(
TexUnpackBlobDesc{target, size, sfer.mAlphaType, {}, {}, {}, dataSurf});
return Some(TexUnpackBlobDesc{target,
size,
sfer.mAlphaType,
{},
{},
elemSize,
layersImage,
sd,
dataSurf});
}
} // namespace webgl
@ -867,8 +913,9 @@ void WebGLTexture::TexImage(uint32_t level, GLenum respecFormat,
cpuDataView = Some(RawBuffer<>{src.cpuData->Data()});
}
const auto srcViewDesc = webgl::TexUnpackBlobDesc{
src.imageTarget, src.size, src.srcAlphaType, std::move(cpuDataView),
src.pboOffset, src.image, src.surf, src.unpacking};
src.imageTarget, src.size, src.srcAlphaType, std::move(cpuDataView),
src.pboOffset, src.imageSize, src.image, src.sd,
src.dataSurf, src.unpacking};
const auto blob = webgl::TexUnpackBlob::Create(srcViewDesc);
if (!blob) {
MOZ_ASSERT(false);
@ -1020,7 +1067,7 @@ void WebGLTexture::TexImage(uint32_t level, GLenum respecFormat,
});
const bool isSubImage = !respecFormat;
GLenum glError;
GLenum glError = 0;
if (!blob->TexOrSubImage(isSubImage, isRespec, this, level, driverUnpackInfo,
offset.x, offset.y, offset.z, pi, &glError)) {
return;

View File

@ -24,6 +24,7 @@
#include "mozilla/gfx/Point.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/ipc/Shmem.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "gfxTypes.h"
#include "nsTArray.h"
@ -298,6 +299,8 @@ class UniqueBuffer {
namespace webgl {
struct FormatUsageInfo;
static constexpr GLenum kErrorPerfWarning = 0x10001;
struct SampleableInfo final {
const char* incompleteReason = nullptr;
uint32_t levels = 0;
@ -536,11 +539,16 @@ struct ReadPixelsDesc final {
PixelPackState packState;
};
class ExtensionBits final {
// -
template <typename E>
class EnumMask {
public:
uint64_t mBits = 0;
private:
struct BitRef final {
ExtensionBits& bits;
EnumMask& bits;
const uint64_t mask;
explicit operator bool() const { return bits.mBits & mask; }
@ -555,15 +563,17 @@ class ExtensionBits final {
}
};
uint64_t Mask(const WebGLExtensionID i) const {
uint64_t Mask(const E i) const {
return uint64_t{1} << static_cast<uint64_t>(i);
}
public:
BitRef operator[](const WebGLExtensionID i) { return {*this, Mask(i)}; }
bool operator[](const WebGLExtensionID i) const { return mBits & Mask(i); }
BitRef operator[](const E i) { return {*this, Mask(i)}; }
bool operator[](const E i) const { return mBits & Mask(i); }
};
class ExtensionBits : public EnumMask<WebGLExtensionID> {};
// -
enum class ContextLossReason : uint8_t {
@ -622,6 +632,7 @@ struct InitContextResult final {
std::string error;
WebGLContextOptions options;
webgl::Limits limits;
EnumMask<layers::SurfaceDescriptor::Type> uploadableSdTypes;
};
// -
@ -970,9 +981,8 @@ struct WebGLPixelStore final {
void Apply(gl::GLContext&, bool isWebgl2, const uvec3& uploadSize) const;
bool AssertCurrent(gl::GLContext&, bool isWebgl2) const;
WebGLPixelStore ForUseWith(
const GLenum target, const uvec3& uploadSize,
const Maybe<gfx::IntSize>& structuredSrcSize) const {
WebGLPixelStore ForUseWith(const GLenum target, const uvec3& uploadSize,
const Maybe<uvec2>& structuredSrcSize) const {
auto ret = *this;
if (!IsTexTarget3D(target)) {
@ -981,7 +991,7 @@ struct WebGLPixelStore final {
}
if (structuredSrcSize) {
ret.mUnpackRowLength = structuredSrcSize->width;
ret.mUnpackRowLength = structuredSrcSize->x;
}
if (!ret.mUnpackRowLength) {
@ -1043,8 +1053,11 @@ struct TexUnpackBlobDesc final {
Maybe<RawBuffer<>> cpuData;
Maybe<uint64_t> pboOffset;
uvec2 imageSize;
RefPtr<layers::Image> image;
RefPtr<gfx::DataSourceSurface> surf;
Maybe<layers::SurfaceDescriptor> sd;
RefPtr<gfx::DataSourceSurface> dataSurf;
WebGLPixelStore unpacking;

View File

@ -221,6 +221,7 @@ if CONFIG["CC_TYPE"] in ("clang", "gcc"):
if CONFIG["CC_TYPE"] in ("clang", "clang-cl"):
CXXFLAGS += ["-Werror=implicit-int-conversion"]
CXXFLAGS += ["-Werror=switch"]
if CONFIG["CC_TYPE"] == "gcc":
CXXFLAGS += ["-Wno-error=unused-result"] # GCC doesn't ignore (void)MustUse();

View File

@ -679,6 +679,41 @@ const DrawBlitProg* GLBlitHelper::CreateDrawBlitProg(
// -----------------------------------------------------------------------------
#ifdef XP_MACOSX
static RefPtr<MacIOSurface> LookupSurface(const layers::SurfaceDescriptorMacIOSurface& sd) {
return MacIOSurface::LookupSurface(
sd.surfaceId(), sd.scaleFactor(),
!sd.isOpaque(), sd.yUVColorSpace());
}
#endif
bool GLBlitHelper::BlitSdToFramebuffer(const layers::SurfaceDescriptor& asd,
const gfx::IntSize& destSize,
const OriginPos destOrigin) {
const auto sdType = asd.type();
switch (sdType) {
#ifdef XP_WIN
case layers::SurfaceDescriptor::TSurfaceDescriptorD3D10: {
const auto& sd = asd.get_SurfaceDescriptorD3D10();
return BlitDescriptor(sd, destSize, destOrigin);
}
case layers::SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr: {
const auto& sd = asd.get_SurfaceDescriptorDXGIYCbCr();
return BlitDescriptor(sd, destSize, destOrigin);
}
#endif
#ifdef XP_MACOSX
case layers::SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
const auto& sd = asd.get_SurfaceDescriptorMacIOSurface();
const auto surf = LookupSurface(sd);
return BlitImage(surf, destSize, destOrigin);
}
#endif
default:
return false;
}
}
bool GLBlitHelper::BlitImageToFramebuffer(layers::Image* const srcImage,
const gfx::IntSize& destSize,
const OriginPos destOrigin) {

View File

@ -39,6 +39,7 @@ class GPUVideoImage;
class PlanarYCbCrImage;
class SurfaceTextureImage;
class MacIOSurfaceImage;
class SurfaceDescriptor;
class SurfaceDescriptorD3D10;
class SurfaceDescriptorDXGIYCbCr;
} // namespace layers
@ -194,6 +195,8 @@ class GLBlitHelper final {
bool BlitImageToFramebuffer(layers::Image* srcImage,
const gfx::IntSize& destSize,
OriginPos destOrigin);
bool BlitSdToFramebuffer(const layers::SurfaceDescriptor&,
const gfx::IntSize& destSize, OriginPos destOrigin);
private:
bool BlitImage(layers::GPUVideoImage* srcImage, const gfx::IntSize& destSize,

View File

@ -64,6 +64,8 @@ class D3D11ShareHandleImage final : public Image {
TextureClient* GetTextureClient(KnowsCompositor* aKnowsCompositor) override;
gfx::IntRect GetPictureRect() const override { return mPictureRect; }
Maybe<SurfaceDescriptor> GetDesc() override { return GetDescFromTexClient(); }
ID3D11Texture2D* GetTexture() const;
gfx::YUVColorSpace GetYUVColorSpace() const { return mYUVColorSpace; }

View File

@ -175,8 +175,6 @@ already_AddRefed<IDirect3DSurface9> D3D9SurfaceImage::GetD3D9Surface() const {
return textureSurface.forget();
}
const D3DSURFACE_DESC& D3D9SurfaceImage::GetDesc() const { return mDesc; }
HANDLE
D3D9SurfaceImage::GetShareHandle() const { return mShareHandle; }

View File

@ -93,8 +93,6 @@ class D3D9SurfaceImage : public Image {
const gfx::IntRect& aRegion);
// Returns the description of the shared surface.
const D3DSURFACE_DESC& GetDesc() const;
gfx::IntSize GetSize() const override;
already_AddRefed<gfx::SourceSurface> GetAsSourceSurface() override;

View File

@ -56,6 +56,10 @@ class GPUVideoImage final : public Image {
gfx::IntSize GetSize() const override { return mSize; }
Maybe<SurfaceDescriptor> GetDesc() override {
return GetDescFromTexClient(mTextureClient);
}
private:
GPUVideoTextureData* GetData() const {
if (!mTextureClient) {

View File

@ -225,6 +225,24 @@ ImageContainer::~ImageContainer() {
}
}
Maybe<SurfaceDescriptor> Image::GetDesc() { return {}; }
Maybe<SurfaceDescriptor> Image::GetDescFromTexClient(
TextureClient* const forTc) {
RefPtr<TextureClient> tc = forTc;
if (!forTc) {
tc = GetTextureClient(nullptr);
}
const auto& tcd = tc->GetInternalData();
SurfaceDescriptor ret;
if (!tcd->Serialize(ret)) {
return {};
}
return Some(ret);
}
RefPtr<PlanarYCbCrImage> ImageContainer::CreatePlanarYCbCrImage() {
RecursiveMutexAutoLock lock(mRecursiveMutex);
EnsureImageClient();

View File

@ -49,6 +49,7 @@ class ImageContainer;
class ImageContainerChild;
class SharedPlanarYCbCrImage;
class SharedSurfacesAnimation;
class SurfaceDescriptor;
class PlanarYCbCrImage;
class TextureClient;
class TextureClientRecycleAllocator;
@ -144,7 +145,12 @@ class Image {
virtual NVImage* AsNVImage() { return nullptr; }
virtual Maybe<SurfaceDescriptor> GetDesc();
protected:
Maybe<SurfaceDescriptor> GetDescFromTexClient(
TextureClient* tcOverride = nullptr);
Image(void* aImplData, ImageFormat aFormat)
: mImplData(aImplData), mSerial(++sSerialCounter), mFormat(aFormat) {}