зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1883225 - webgl.texSubImage(video): re-enable gpu-blit for RGBA, and RGB iff RGB8+SRGB8 renderable. r=gfx-reviewers,lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D203698
This commit is contained in:
Родитель
c88bbf7a75
Коммит
e23c373711
|
@ -1268,8 +1268,9 @@ RefPtr<gfx::DataSourceSurface> ClientWebGLContext::BackBufferSnapshot() {
|
||||||
if (!DoReadPixels(desc, pixels)) return nullptr;
|
if (!DoReadPixels(desc, pixels)) return nullptr;
|
||||||
|
|
||||||
// RGBA->BGRA and flip-y.
|
// RGBA->BGRA and flip-y.
|
||||||
MOZ_RELEASE_ASSERT(gfx::SwizzleYFlipData(pixels.data(), stride, gfx::SurfaceFormat::R8G8B8A8,
|
MOZ_RELEASE_ASSERT(gfx::SwizzleYFlipData(
|
||||||
pixels.data(), stride, gfx::SurfaceFormat::B8G8R8A8, {size.x, size.y}));
|
pixels.data(), stride, gfx::SurfaceFormat::R8G8B8A8, pixels.data(),
|
||||||
|
stride, gfx::SurfaceFormat::B8G8R8A8, {size.x, size.y}));
|
||||||
}
|
}
|
||||||
|
|
||||||
return surf;
|
return surf;
|
||||||
|
@ -4356,12 +4357,9 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
|
||||||
const auto& contextInfo = mNotLost->info;
|
const auto& contextInfo = mNotLost->info;
|
||||||
|
|
||||||
const auto fallbackReason = [&]() -> Maybe<std::string> {
|
const auto fallbackReason = [&]() -> Maybe<std::string> {
|
||||||
if (!respecFormat) {
|
auto fallbackReason =
|
||||||
return Some(std::string{
|
BlitPreventReason(level, offset, respecFormat, pi, *desc,
|
||||||
"Fast uploads not supported for TexSubImage. Use TexImage."});
|
contextInfo.optionalRenderableFormatBits);
|
||||||
}
|
|
||||||
auto fallbackReason = BlitPreventReason(
|
|
||||||
level, offset, respecFormat, pi, *desc, contextInfo.isRgb8Renderable);
|
|
||||||
if (fallbackReason) return fallbackReason;
|
if (fallbackReason) return fallbackReason;
|
||||||
|
|
||||||
const bool canUploadViaSd = contextInfo.uploadableSdTypes[sdType];
|
const bool canUploadViaSd = contextInfo.uploadableSdTypes[sdType];
|
||||||
|
|
|
@ -668,11 +668,10 @@ bool TexUnpackImage::Validate(const WebGLContext* const webgl,
|
||||||
return ValidateUnpackPixels(webgl, pi, fullRows, *this);
|
return ValidateUnpackPixels(webgl, pi, fullRows, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Maybe<std::string> BlitPreventReason(const int32_t level, const ivec3& offset,
|
Maybe<std::string> BlitPreventReason(
|
||||||
const GLenum internalFormat,
|
const int32_t level, const ivec3& offset, const GLenum internalFormat,
|
||||||
const webgl::PackingInfo& pi,
|
const webgl::PackingInfo& pi, const TexUnpackBlobDesc& desc,
|
||||||
const TexUnpackBlobDesc& desc,
|
const OptionalRenderableFormatBits optionalRenderableFormatBits) {
|
||||||
const bool isRgb8Renderable) {
|
|
||||||
const auto& size = desc.size;
|
const auto& size = desc.size;
|
||||||
const auto& unpacking = desc.unpacking;
|
const auto& unpacking = desc.unpacking;
|
||||||
|
|
||||||
|
@ -705,26 +704,71 @@ Maybe<std::string> BlitPreventReason(const int32_t level, const ivec3& offset,
|
||||||
|
|
||||||
const auto formatReason = [&]() -> const char* {
|
const auto formatReason = [&]() -> const char* {
|
||||||
if (pi.type != LOCAL_GL_UNSIGNED_BYTE) {
|
if (pi.type != LOCAL_GL_UNSIGNED_BYTE) {
|
||||||
return "`type` must be `UNSIGNED_BYTE`";
|
return "`unpackType` must be `UNSIGNED_BYTE`";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (internalFormat) {
|
switch (pi.format) {
|
||||||
case LOCAL_GL_RGBA:
|
case LOCAL_GL_RGBA:
|
||||||
case LOCAL_GL_RGBA8:
|
return nullptr; // All internalFormats for unpackFormat=RGBA are
|
||||||
return nullptr;
|
// renderable.
|
||||||
|
|
||||||
case LOCAL_GL_RGB:
|
case LOCAL_GL_RGB:
|
||||||
case LOCAL_GL_RGB8:
|
|
||||||
if (isRgb8Renderable) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "`unpackFormat` must be `RGBA` or maybe `RGB`";
|
||||||
}
|
}
|
||||||
if (isRgb8Renderable) {
|
|
||||||
return "effective format must be RGB8 or RGBA8";
|
// -
|
||||||
} else {
|
|
||||||
return "effective format must be RGBA8";
|
struct {
|
||||||
|
OptionalRenderableFormatBits bits;
|
||||||
|
const char* errorMsg;
|
||||||
|
} required;
|
||||||
|
|
||||||
|
switch (internalFormat) {
|
||||||
|
case LOCAL_GL_RGB565:
|
||||||
|
return nullptr;
|
||||||
|
case LOCAL_GL_RGB:
|
||||||
|
case LOCAL_GL_RGB8:
|
||||||
|
required = {
|
||||||
|
OptionalRenderableFormatBits::RGB8,
|
||||||
|
"Unavailable, as blitting internalFormats RGB or RGB8 requires "
|
||||||
|
"that RGB8 must be a renderable format.",
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case LOCAL_GL_SRGB:
|
||||||
|
case LOCAL_GL_SRGB8:
|
||||||
|
required = {
|
||||||
|
OptionalRenderableFormatBits::SRGB8,
|
||||||
|
"Unavailable, as blitting internalFormats SRGB or SRGB8 requires "
|
||||||
|
"that SRGB8 must be a renderable format.",
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
// texSubImage, so internalFormat is unknown, and could be anything!
|
||||||
|
required = {
|
||||||
|
OptionalRenderableFormatBits::RGB8 |
|
||||||
|
OptionalRenderableFormatBits::SRGB8,
|
||||||
|
"Unavailable, as blitting texSubImage with unpackFormat=RGB "
|
||||||
|
"requires that RGB8 and SRGB8 must be renderable formats.",
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gfxCriticalError()
|
||||||
|
<< "Unexpected internalFormat for unpackFormat=RGB: 0x"
|
||||||
|
<< gfx::hexa(internalFormat);
|
||||||
|
return "Unexpected internalFormat for unpackFormat=RGB";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto availableBits = optionalRenderableFormatBits;
|
||||||
|
if ((required.bits | availableBits) != availableBits) {
|
||||||
|
return required.errorMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
}();
|
}();
|
||||||
if (formatReason) return formatReason;
|
if (formatReason) return formatReason;
|
||||||
|
|
||||||
|
@ -756,7 +800,7 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
|
||||||
|
|
||||||
const auto reason =
|
const auto reason =
|
||||||
BlitPreventReason(level, {xOffset, yOffset, zOffset}, dui->internalFormat,
|
BlitPreventReason(level, {xOffset, yOffset, zOffset}, dui->internalFormat,
|
||||||
pi, mDesc, webgl->mIsRgb8Renderable);
|
pi, mDesc, webgl->mOptionalRenderableFormatBits);
|
||||||
if (reason) {
|
if (reason) {
|
||||||
webgl->GeneratePerfWarning(
|
webgl->GeneratePerfWarning(
|
||||||
"Failed to hit GPU-copy fast-path."
|
"Failed to hit GPU-copy fast-path."
|
||||||
|
|
|
@ -45,7 +45,7 @@ Maybe<std::string> BlitPreventReason(int32_t level, const ivec3& offset,
|
||||||
GLenum internalFormat,
|
GLenum internalFormat,
|
||||||
const webgl::PackingInfo&,
|
const webgl::PackingInfo&,
|
||||||
const TexUnpackBlobDesc&,
|
const TexUnpackBlobDesc&,
|
||||||
bool isRgb8Renderable);
|
OptionalRenderableFormatBits);
|
||||||
|
|
||||||
class TexUnpackBlob {
|
class TexUnpackBlob {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -653,7 +653,7 @@ RefPtr<WebGLContext> WebGLContext::Create(HostWebGLContext* host,
|
||||||
out->limits = *webgl->mLimits;
|
out->limits = *webgl->mLimits;
|
||||||
out->uploadableSdTypes = UploadableSdTypes();
|
out->uploadableSdTypes = UploadableSdTypes();
|
||||||
out->vendor = webgl->gl->Vendor();
|
out->vendor = webgl->gl->Vendor();
|
||||||
out->isRgb8Renderable = webgl->mIsRgb8Renderable;
|
out->optionalRenderableFormatBits = webgl->mOptionalRenderableFormatBits;
|
||||||
|
|
||||||
return webgl;
|
return webgl;
|
||||||
}
|
}
|
||||||
|
@ -710,15 +710,36 @@ void WebGLContext::FinishInit() {
|
||||||
const auto tex = gl::ScopedTexture(gl);
|
const auto tex = gl::ScopedTexture(gl);
|
||||||
const auto fb = gl::ScopedFramebuffer(gl);
|
const auto fb = gl::ScopedFramebuffer(gl);
|
||||||
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, tex);
|
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, tex);
|
||||||
gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGB, 1, 1, 0, LOCAL_GL_RGB,
|
|
||||||
LOCAL_GL_UNSIGNED_BYTE, nullptr);
|
|
||||||
|
|
||||||
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
|
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, fb);
|
||||||
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
|
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
|
||||||
LOCAL_GL_TEXTURE_2D, tex, 0);
|
LOCAL_GL_TEXTURE_2D, tex, 0);
|
||||||
|
|
||||||
const auto status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
const auto IsRenderable = [&](const GLint internalFormat,
|
||||||
mIsRgb8Renderable = (status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
|
const GLenum unpackFormat) {
|
||||||
|
gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, internalFormat, 1, 1, 0,
|
||||||
|
unpackFormat, LOCAL_GL_UNSIGNED_BYTE, nullptr);
|
||||||
|
const auto status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||||
|
return (status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (IsRenderable(LOCAL_GL_RGB, LOCAL_GL_RGB)) {
|
||||||
|
mOptionalRenderableFormatBits |=
|
||||||
|
webgl::OptionalRenderableFormatBits::RGB8;
|
||||||
|
}
|
||||||
|
if (gl->IsSupported(gl::GLFeature::sRGB)) {
|
||||||
|
struct {
|
||||||
|
GLint internal;
|
||||||
|
GLenum unpack;
|
||||||
|
} formats = {LOCAL_GL_SRGB8, LOCAL_GL_RGB};
|
||||||
|
const bool isEs2 = (gl->IsGLES() && gl->Version() < 300);
|
||||||
|
if (isEs2) {
|
||||||
|
formats = {LOCAL_GL_SRGB, LOCAL_GL_SRGB};
|
||||||
|
}
|
||||||
|
if (IsRenderable(formats.internal, formats.unpack)) {
|
||||||
|
mOptionalRenderableFormatBits |=
|
||||||
|
webgl::OptionalRenderableFormatBits::SRGB8;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//////
|
//////
|
||||||
|
|
|
@ -317,7 +317,8 @@ class WebGLContext : public VRefCounted, public SupportsWeakPtr {
|
||||||
webgl::InitContextResult* out);
|
webgl::InitContextResult* out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool mIsRgb8Renderable = false;
|
webgl::OptionalRenderableFormatBits mOptionalRenderableFormatBits =
|
||||||
|
webgl::OptionalRenderableFormatBits{0};
|
||||||
void FinishInit();
|
void FinishInit();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -641,6 +641,35 @@ struct ParamTraits<mozilla::avec3<U>> final {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -
|
||||||
|
|
||||||
|
template <class TT>
|
||||||
|
struct ParamTraits_IsEnumCase {
|
||||||
|
using T = TT;
|
||||||
|
|
||||||
|
static void Write(IPC::MessageWriter* const writer, const T& in) {
|
||||||
|
MOZ_RELEASE_ASSERT(IsEnumCase(in));
|
||||||
|
WriteParam(writer, mozilla::UnderlyingValue(in));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool Read(IPC::MessageReader* const reader, T* const out) {
|
||||||
|
std::underlying_type_t<T> rawVal;
|
||||||
|
if (!ReadParam(reader, &rawVal)) return false;
|
||||||
|
*out = static_cast<T>(rawVal);
|
||||||
|
return IsEnumCase(*out);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// -
|
||||||
|
|
||||||
|
#define USE_IS_ENUM_CASE(T) \
|
||||||
|
template <> \
|
||||||
|
struct ParamTraits<T> : public ParamTraits_IsEnumCase<T> {};
|
||||||
|
|
||||||
|
USE_IS_ENUM_CASE(mozilla::webgl::OptionalRenderableFormatBits)
|
||||||
|
|
||||||
|
#undef USE_IS_ENUM_CASE
|
||||||
|
|
||||||
} // namespace IPC
|
} // namespace IPC
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -19,12 +19,14 @@
|
||||||
#include "ImageContainer.h"
|
#include "ImageContainer.h"
|
||||||
#include "mozilla/Casting.h"
|
#include "mozilla/Casting.h"
|
||||||
#include "mozilla/CheckedInt.h"
|
#include "mozilla/CheckedInt.h"
|
||||||
|
#include "mozilla/EnumTypeTraits.h"
|
||||||
#include "mozilla/MathAlgorithms.h"
|
#include "mozilla/MathAlgorithms.h"
|
||||||
#include "mozilla/Range.h"
|
#include "mozilla/Range.h"
|
||||||
#include "mozilla/RefCounted.h"
|
#include "mozilla/RefCounted.h"
|
||||||
#include "mozilla/Result.h"
|
#include "mozilla/Result.h"
|
||||||
#include "mozilla/ResultVariant.h"
|
#include "mozilla/ResultVariant.h"
|
||||||
#include "mozilla/Span.h"
|
#include "mozilla/Span.h"
|
||||||
|
#include "mozilla/TypedEnumBits.h"
|
||||||
#include "mozilla/gfx/2D.h"
|
#include "mozilla/gfx/2D.h"
|
||||||
#include "mozilla/gfx/BuildConstants.h"
|
#include "mozilla/gfx/BuildConstants.h"
|
||||||
#include "mozilla/gfx/Logging.h"
|
#include "mozilla/gfx/Logging.h"
|
||||||
|
@ -679,18 +681,41 @@ struct Padded {
|
||||||
|
|
||||||
// -
|
// -
|
||||||
|
|
||||||
|
enum class OptionalRenderableFormatBits : uint8_t {
|
||||||
|
RGB8 = (1 << 0),
|
||||||
|
SRGB8 = (1 << 1),
|
||||||
|
};
|
||||||
|
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(OptionalRenderableFormatBits)
|
||||||
|
inline constexpr bool IsEnumCase(const OptionalRenderableFormatBits raw) {
|
||||||
|
auto rawWithoutValidBits = UnderlyingValue(raw);
|
||||||
|
auto bit = decltype(rawWithoutValidBits){1};
|
||||||
|
while (bit) {
|
||||||
|
switch (OptionalRenderableFormatBits{bit}) {
|
||||||
|
// -Werror=switch ensures exhaustive.
|
||||||
|
case OptionalRenderableFormatBits::RGB8:
|
||||||
|
case OptionalRenderableFormatBits::SRGB8:
|
||||||
|
rawWithoutValidBits &= ~bit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bit <<= 1;
|
||||||
|
}
|
||||||
|
return rawWithoutValidBits == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// -
|
||||||
|
|
||||||
struct InitContextResult final {
|
struct InitContextResult final {
|
||||||
Padded<std::string, 32> error; // MINGW 32-bit needs this padding.
|
Padded<std::string, 32> error; // MINGW 32-bit needs this padding.
|
||||||
WebGLContextOptions options;
|
WebGLContextOptions options;
|
||||||
gl::GLVendor vendor;
|
gl::GLVendor vendor;
|
||||||
bool isRgb8Renderable;
|
OptionalRenderableFormatBits optionalRenderableFormatBits;
|
||||||
uint8_t _padding = {};
|
uint8_t _padding = {};
|
||||||
webgl::Limits limits;
|
Limits limits;
|
||||||
EnumMask<layers::SurfaceDescriptor::Type> uploadableSdTypes;
|
EnumMask<layers::SurfaceDescriptor::Type> uploadableSdTypes;
|
||||||
|
|
||||||
auto MutTiedFields() {
|
auto MutTiedFields() {
|
||||||
return std::tie(error, options, vendor, isRgb8Renderable, _padding, limits,
|
return std::tie(error, options, vendor, optionalRenderableFormatBits,
|
||||||
uploadableSdTypes);
|
_padding, limits, uploadableSdTypes);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче