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:
Kelsey Gilbert 2024-03-09 05:35:20 +00:00
Родитель c88bbf7a75
Коммит e23c373711
7 изменённых файлов: 156 добавлений и 38 удалений

Просмотреть файл

@ -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);
} }
}; };