зеркало из 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;
|
||||
|
||||
// RGBA->BGRA and flip-y.
|
||||
MOZ_RELEASE_ASSERT(gfx::SwizzleYFlipData(pixels.data(), stride, gfx::SurfaceFormat::R8G8B8A8,
|
||||
pixels.data(), stride, gfx::SurfaceFormat::B8G8R8A8, {size.x, size.y}));
|
||||
MOZ_RELEASE_ASSERT(gfx::SwizzleYFlipData(
|
||||
pixels.data(), stride, gfx::SurfaceFormat::R8G8B8A8, pixels.data(),
|
||||
stride, gfx::SurfaceFormat::B8G8R8A8, {size.x, size.y}));
|
||||
}
|
||||
|
||||
return surf;
|
||||
|
@ -4356,12 +4357,9 @@ void ClientWebGLContext::TexImage(uint8_t funcDims, GLenum imageTarget,
|
|||
const auto& contextInfo = mNotLost->info;
|
||||
|
||||
const auto fallbackReason = [&]() -> Maybe<std::string> {
|
||||
if (!respecFormat) {
|
||||
return Some(std::string{
|
||||
"Fast uploads not supported for TexSubImage. Use TexImage."});
|
||||
}
|
||||
auto fallbackReason = BlitPreventReason(
|
||||
level, offset, respecFormat, pi, *desc, contextInfo.isRgb8Renderable);
|
||||
auto fallbackReason =
|
||||
BlitPreventReason(level, offset, respecFormat, pi, *desc,
|
||||
contextInfo.optionalRenderableFormatBits);
|
||||
if (fallbackReason) return fallbackReason;
|
||||
|
||||
const bool canUploadViaSd = contextInfo.uploadableSdTypes[sdType];
|
||||
|
|
|
@ -668,11 +668,10 @@ bool TexUnpackImage::Validate(const WebGLContext* const webgl,
|
|||
return ValidateUnpackPixels(webgl, pi, fullRows, *this);
|
||||
}
|
||||
|
||||
Maybe<std::string> BlitPreventReason(const int32_t level, const ivec3& offset,
|
||||
const GLenum internalFormat,
|
||||
const webgl::PackingInfo& pi,
|
||||
const TexUnpackBlobDesc& desc,
|
||||
const bool isRgb8Renderable) {
|
||||
Maybe<std::string> BlitPreventReason(
|
||||
const int32_t level, const ivec3& offset, const GLenum internalFormat,
|
||||
const webgl::PackingInfo& pi, const TexUnpackBlobDesc& desc,
|
||||
const OptionalRenderableFormatBits optionalRenderableFormatBits) {
|
||||
const auto& size = desc.size;
|
||||
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* {
|
||||
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_RGBA8:
|
||||
return nullptr;
|
||||
return nullptr; // All internalFormats for unpackFormat=RGBA are
|
||||
// renderable.
|
||||
|
||||
case LOCAL_GL_RGB:
|
||||
case LOCAL_GL_RGB8:
|
||||
if (isRgb8Renderable) {
|
||||
return nullptr;
|
||||
}
|
||||
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;
|
||||
|
||||
|
@ -756,7 +800,7 @@ bool TexUnpackImage::TexOrSubImage(bool isSubImage, bool needsRespec,
|
|||
|
||||
const auto reason =
|
||||
BlitPreventReason(level, {xOffset, yOffset, zOffset}, dui->internalFormat,
|
||||
pi, mDesc, webgl->mIsRgb8Renderable);
|
||||
pi, mDesc, webgl->mOptionalRenderableFormatBits);
|
||||
if (reason) {
|
||||
webgl->GeneratePerfWarning(
|
||||
"Failed to hit GPU-copy fast-path."
|
||||
|
|
|
@ -45,7 +45,7 @@ Maybe<std::string> BlitPreventReason(int32_t level, const ivec3& offset,
|
|||
GLenum internalFormat,
|
||||
const webgl::PackingInfo&,
|
||||
const TexUnpackBlobDesc&,
|
||||
bool isRgb8Renderable);
|
||||
OptionalRenderableFormatBits);
|
||||
|
||||
class TexUnpackBlob {
|
||||
public:
|
||||
|
|
|
@ -653,7 +653,7 @@ RefPtr<WebGLContext> WebGLContext::Create(HostWebGLContext* host,
|
|||
out->limits = *webgl->mLimits;
|
||||
out->uploadableSdTypes = UploadableSdTypes();
|
||||
out->vendor = webgl->gl->Vendor();
|
||||
out->isRgb8Renderable = webgl->mIsRgb8Renderable;
|
||||
out->optionalRenderableFormatBits = webgl->mOptionalRenderableFormatBits;
|
||||
|
||||
return webgl;
|
||||
}
|
||||
|
@ -710,15 +710,36 @@ void WebGLContext::FinishInit() {
|
|||
const auto tex = gl::ScopedTexture(gl);
|
||||
const auto fb = gl::ScopedFramebuffer(gl);
|
||||
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->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
|
||||
LOCAL_GL_TEXTURE_2D, tex, 0);
|
||||
|
||||
const auto status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
mIsRgb8Renderable = (status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
|
||||
const auto IsRenderable = [&](const GLint internalFormat,
|
||||
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);
|
||||
|
||||
private:
|
||||
bool mIsRgb8Renderable = false;
|
||||
webgl::OptionalRenderableFormatBits mOptionalRenderableFormatBits =
|
||||
webgl::OptionalRenderableFormatBits{0};
|
||||
void FinishInit();
|
||||
|
||||
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
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
#include "ImageContainer.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/EnumTypeTraits.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/Range.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
#include "mozilla/Result.h"
|
||||
#include "mozilla/ResultVariant.h"
|
||||
#include "mozilla/Span.h"
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/BuildConstants.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 {
|
||||
Padded<std::string, 32> error; // MINGW 32-bit needs this padding.
|
||||
WebGLContextOptions options;
|
||||
gl::GLVendor vendor;
|
||||
bool isRgb8Renderable;
|
||||
OptionalRenderableFormatBits optionalRenderableFormatBits;
|
||||
uint8_t _padding = {};
|
||||
webgl::Limits limits;
|
||||
Limits limits;
|
||||
EnumMask<layers::SurfaceDescriptor::Type> uploadableSdTypes;
|
||||
|
||||
auto MutTiedFields() {
|
||||
return std::tie(error, options, vendor, isRgb8Renderable, _padding, limits,
|
||||
uploadableSdTypes);
|
||||
return std::tie(error, options, vendor, optionalRenderableFormatBits,
|
||||
_padding, limits, uploadableSdTypes);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче