mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-25 01:47:31 +09:00
CWebRender pt2
This commit is contained in:
parent
1190eb1c6a
commit
fe181d242f
22 changed files with 1623 additions and 489 deletions
|
|
@ -90,8 +90,10 @@ def get_sdk_dirs(sdk, subdir):
|
||||||
return int(parts[2]) if len(parts) >= 3 else 0
|
return int(parts[2]) if len(parts) >= 3 else 0
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return 0
|
return 0
|
||||||
|
# Keep compatibility with the current Windows 11 SDK while retaining an
|
||||||
|
# upper bound for SDK layouts this older tree has not been audited against.
|
||||||
valid_versions = sorted((v for v in set(include_dirs) & set(lib_dirs)
|
valid_versions = sorted((v for v in set(include_dirs) & set(lib_dirs)
|
||||||
if build_num(v) <= 19041), reverse=True)
|
if build_num(v) <= 26100), reverse=True)
|
||||||
if valid_versions:
|
if valid_versions:
|
||||||
return namespace(
|
return namespace(
|
||||||
path=sdk,
|
path=sdk,
|
||||||
|
|
@ -149,7 +151,7 @@ def valid_windows_sdk_dir(compiler, windows_sdk_dir, target_version,
|
||||||
return int(parts[2]) if len(parts) >= 3 else 0
|
return int(parts[2]) if len(parts) >= 3 else 0
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return 0
|
return 0
|
||||||
sdks = {k: v for k, v in sdks.items() if sdk_build(k) <= 19041}
|
sdks = {k: v for k, v in sdks.items() if sdk_build(k) <= 26100}
|
||||||
valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
|
valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
|
||||||
if valid_sdks:
|
if valid_sdks:
|
||||||
biggest_version, sdk = sdks[valid_sdks[0]]
|
biggest_version, sdk = sdks[valid_sdks[0]]
|
||||||
|
|
@ -240,7 +242,8 @@ def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env):
|
||||||
'The SDK in WINDOWSSDKDIR (%s) does not contain the Universal '
|
'The SDK in WINDOWSSDKDIR (%s) does not contain the Universal '
|
||||||
'CRT.' % windows_sdk_dir_env)
|
'CRT.' % windows_sdk_dir_env)
|
||||||
|
|
||||||
sdks = {k: v for k, v in sdks.items() if int(str(v[0]).split('.')[2]) <= 19041}
|
sdks = {k: v for k, v in sdks.items()
|
||||||
|
if int(str(v[0]).split('.')[2]) <= 26100}
|
||||||
valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
|
valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
|
||||||
if not valid_sdks:
|
if not valid_sdks:
|
||||||
raise FatalCheckError('Cannot find the Universal CRT SDK. '
|
raise FatalCheckError('Cannot find the Universal CRT SDK. '
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,14 @@
|
||||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||||
#include "mozilla/gfx/BaseRect.h" // for BaseRect
|
#include "mozilla/gfx/BaseRect.h" // for BaseRect
|
||||||
#include "mozilla/layers/Compositor.h" // for Compositor
|
#include "mozilla/layers/Compositor.h" // for Compositor
|
||||||
|
#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
|
||||||
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
|
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
|
||||||
#include "mozilla/layers/LayersMessages.h" // for ThebesBufferData
|
#include "mozilla/layers/LayersMessages.h" // for ThebesBufferData
|
||||||
#include "nsAString.h"
|
#include "nsAString.h"
|
||||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||||
#include "nsString.h" // for nsAutoCString
|
#include "nsString.h" // for nsAutoCString
|
||||||
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
||||||
|
#include "gfxPrefs.h" // for gfxPrefs::WebRenderEnabled
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
using namespace gfx;
|
using namespace gfx;
|
||||||
|
|
@ -69,6 +71,15 @@ ContentHostTexture::Composite(LayerComposite* aLayer,
|
||||||
|
|
||||||
aEffectChain.mPrimaryEffect = effect;
|
aEffectChain.mPrimaryEffect = effect;
|
||||||
|
|
||||||
|
CompositorOGL* compositorOGL = GetCompositor()->AsCompositorOGL();
|
||||||
|
bool canUseWebRender =
|
||||||
|
gfxPrefs::WebRenderEnabled() && compositorOGL &&
|
||||||
|
effect->mType == EffectTypes::RGB && !mTextureSourceOnWhite &&
|
||||||
|
!mTextureSource->AsBigImageIterator() && aTransform.Is2D() &&
|
||||||
|
!aEffectChain.mSecondaryEffects[EffectTypes::MASK] &&
|
||||||
|
!aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE] &&
|
||||||
|
aSamplingFilter == SamplingFilter::LINEAR;
|
||||||
|
|
||||||
nsIntRegion tmpRegion;
|
nsIntRegion tmpRegion;
|
||||||
const nsIntRegion* renderRegion;
|
const nsIntRegion* renderRegion;
|
||||||
if (PaintWillResample()) {
|
if (PaintWillResample()) {
|
||||||
|
|
@ -176,7 +187,13 @@ ContentHostTexture::Composite(LayerComposite* aLayer,
|
||||||
Float(tileRegionRect.y) / texRect.height,
|
Float(tileRegionRect.y) / texRect.height,
|
||||||
Float(tileRegionRect.width) / texRect.width,
|
Float(tileRegionRect.width) / texRect.width,
|
||||||
Float(tileRegionRect.height) / texRect.height);
|
Float(tileRegionRect.height) / texRect.height);
|
||||||
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain, aOpacity, aTransform);
|
if (!canUseWebRender ||
|
||||||
|
!compositorOGL->DrawWebRenderImage(
|
||||||
|
effect->mTexture, rect, effect->mTextureCoords, aOpacity,
|
||||||
|
aTransform, aClipRect, effect->mPremultiplied)) {
|
||||||
|
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain,
|
||||||
|
aOpacity, aTransform);
|
||||||
|
}
|
||||||
if (usingTiles) {
|
if (usingTiles) {
|
||||||
DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT | DiagnosticFlags::BIGIMAGE;
|
DiagnosticFlags diagnostics = DiagnosticFlags::CONTENT | DiagnosticFlags::BIGIMAGE;
|
||||||
if (iterOnWhite) {
|
if (iterOnWhite) {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include "composite/CompositableHost.h" // for CompositableHost, etc
|
#include "composite/CompositableHost.h" // for CompositableHost, etc
|
||||||
#include "ipc/IPCMessageUtils.h" // for null_t
|
#include "ipc/IPCMessageUtils.h" // for null_t
|
||||||
#include "mozilla/layers/Compositor.h" // for Compositor
|
#include "mozilla/layers/Compositor.h" // for Compositor
|
||||||
|
#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
|
||||||
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
|
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
|
||||||
#include "mozilla/layers/ImageContainerParent.h"
|
#include "mozilla/layers/ImageContainerParent.h"
|
||||||
#include "mozilla/layers/LayerManagerComposite.h" // for TexturedEffect, Effect, etc
|
#include "mozilla/layers/LayerManagerComposite.h" // for TexturedEffect, Effect, etc
|
||||||
|
|
@ -16,6 +17,7 @@
|
||||||
#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
|
#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
|
||||||
#include "nsPrintfCString.h" // for nsPrintfCString
|
#include "nsPrintfCString.h" // for nsPrintfCString
|
||||||
#include "nsString.h" // for nsAutoCString
|
#include "nsString.h" // for nsAutoCString
|
||||||
|
#include "gfxPrefs.h" // for gfxPrefs::WebRenderEnabled
|
||||||
|
|
||||||
#define BIAS_TIME_MS 1.0
|
#define BIAS_TIME_MS 1.0
|
||||||
|
|
||||||
|
|
@ -381,6 +383,16 @@ ImageHost::Composite(LayerComposite* aLayer,
|
||||||
mLastProducerID = img->mProducerID;
|
mLastProducerID = img->mProducerID;
|
||||||
}
|
}
|
||||||
aEffectChain.mPrimaryEffect = effect;
|
aEffectChain.mPrimaryEffect = effect;
|
||||||
|
CompositorOGL* compositorOGL = GetCompositor()->AsCompositorOGL();
|
||||||
|
auto drawWebRenderImage = [&](const gfx::Rect& rect) {
|
||||||
|
return gfxPrefs::WebRenderEnabled() && compositorOGL &&
|
||||||
|
effect->mType == EffectTypes::RGB && aTransform.Is2D() &&
|
||||||
|
!aEffectChain.mSecondaryEffects[EffectTypes::MASK] &&
|
||||||
|
!aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE] &&
|
||||||
|
compositorOGL->DrawWebRenderImage(
|
||||||
|
effect->mTexture, rect, effect->mTextureCoords, aOpacity,
|
||||||
|
aTransform, aClipRect, effect->mPremultiplied);
|
||||||
|
};
|
||||||
gfx::Rect pictureRect(0, 0, img->mPictureRect.width, img->mPictureRect.height);
|
gfx::Rect pictureRect(0, 0, img->mPictureRect.width, img->mPictureRect.height);
|
||||||
BigImageIterator* it = mCurrentTextureSource->AsBigImageIterator();
|
BigImageIterator* it = mCurrentTextureSource->AsBigImageIterator();
|
||||||
if (it) {
|
if (it) {
|
||||||
|
|
@ -414,8 +426,10 @@ ImageHost::Composite(LayerComposite* aLayer,
|
||||||
effect->mTextureCoords.y = effect->mTextureCoords.YMost();
|
effect->mTextureCoords.y = effect->mTextureCoords.YMost();
|
||||||
effect->mTextureCoords.height = -effect->mTextureCoords.height;
|
effect->mTextureCoords.height = -effect->mTextureCoords.height;
|
||||||
}
|
}
|
||||||
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain,
|
if (!drawWebRenderImage(rect)) {
|
||||||
aOpacity, aTransform);
|
GetCompositor()->DrawQuad(rect, aClipRect, aEffectChain,
|
||||||
|
aOpacity, aTransform);
|
||||||
|
}
|
||||||
GetCompositor()->DrawDiagnostics(diagnosticFlags | DiagnosticFlags::BIGIMAGE,
|
GetCompositor()->DrawDiagnostics(diagnosticFlags | DiagnosticFlags::BIGIMAGE,
|
||||||
rect, aClipRect, aTransform, mFlashCounter);
|
rect, aClipRect, aTransform, mFlashCounter);
|
||||||
} while (it->NextTile());
|
} while (it->NextTile());
|
||||||
|
|
@ -435,8 +449,10 @@ ImageHost::Composite(LayerComposite* aLayer,
|
||||||
effect->mTextureCoords.height = -effect->mTextureCoords.height;
|
effect->mTextureCoords.height = -effect->mTextureCoords.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
GetCompositor()->DrawQuad(pictureRect, aClipRect, aEffectChain,
|
if (!drawWebRenderImage(pictureRect)) {
|
||||||
aOpacity, aTransform);
|
GetCompositor()->DrawQuad(pictureRect, aClipRect, aEffectChain,
|
||||||
|
aOpacity, aTransform);
|
||||||
|
}
|
||||||
GetCompositor()->DrawDiagnostics(diagnosticFlags,
|
GetCompositor()->DrawDiagnostics(diagnosticFlags,
|
||||||
pictureRect, aClipRect,
|
pictureRect, aClipRect,
|
||||||
aTransform, mFlashCounter);
|
aTransform, mFlashCounter);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||||
#include "mozilla/gfx/Point.h" // for IntSize
|
#include "mozilla/gfx/Point.h" // for IntSize
|
||||||
#include "mozilla/layers/Compositor.h" // for Compositor
|
#include "mozilla/layers/Compositor.h" // for Compositor
|
||||||
|
#include "mozilla/layers/CompositorOGL.h" // for CompositorOGL
|
||||||
//#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent
|
//#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent
|
||||||
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
|
#include "mozilla/layers/Effects.h" // for TexturedEffect, Effect, etc
|
||||||
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
#include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
|
||||||
|
|
@ -486,6 +487,15 @@ TiledContentHost::RenderTile(TileHost& aTile,
|
||||||
float opacity = aTile.GetFadeInOpacity(aOpacity);
|
float opacity = aTile.GetFadeInOpacity(aOpacity);
|
||||||
aEffectChain.mPrimaryEffect = effect;
|
aEffectChain.mPrimaryEffect = effect;
|
||||||
|
|
||||||
|
CompositorOGL* compositorOGL = mCompositor->AsCompositorOGL();
|
||||||
|
bool canUseWebRender =
|
||||||
|
gfxPrefs::WebRenderEnabled() && compositorOGL &&
|
||||||
|
effect->mType == EffectTypes::RGB && !aTile.mTextureHostOnWhite &&
|
||||||
|
aTransform.Is2D() &&
|
||||||
|
!aEffectChain.mSecondaryEffects[EffectTypes::MASK] &&
|
||||||
|
!aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE] &&
|
||||||
|
aSamplingFilter == gfx::SamplingFilter::LINEAR;
|
||||||
|
|
||||||
for (auto iter = aScreenRegion.RectIter(); !iter.Done(); iter.Next()) {
|
for (auto iter = aScreenRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||||
const IntRect& rect = iter.Get();
|
const IntRect& rect = iter.Get();
|
||||||
Rect graphicsRect(rect.x, rect.y, rect.width, rect.height);
|
Rect graphicsRect(rect.x, rect.y, rect.width, rect.height);
|
||||||
|
|
@ -496,7 +506,13 @@ TiledContentHost::RenderTile(TileHost& aTile,
|
||||||
textureRect.y / aTextureBounds.height,
|
textureRect.y / aTextureBounds.height,
|
||||||
textureRect.width / aTextureBounds.width,
|
textureRect.width / aTextureBounds.width,
|
||||||
textureRect.height / aTextureBounds.height);
|
textureRect.height / aTextureBounds.height);
|
||||||
mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, opacity, aTransform, aVisibleRect);
|
if (!canUseWebRender ||
|
||||||
|
!compositorOGL->DrawWebRenderImage(
|
||||||
|
effect->mTexture, graphicsRect, effect->mTextureCoords, opacity,
|
||||||
|
aTransform, aClipRect, effect->mPremultiplied)) {
|
||||||
|
mCompositor->DrawQuad(graphicsRect, aClipRect, aEffectChain, opacity,
|
||||||
|
aTransform, aVisibleRect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
DiagnosticFlags flags = DiagnosticFlags::CONTENT | DiagnosticFlags::TILE;
|
DiagnosticFlags flags = DiagnosticFlags::CONTENT | DiagnosticFlags::TILE;
|
||||||
if (aTile.mTextureHostOnWhite) {
|
if (aTile.mTextureHostOnWhite) {
|
||||||
|
|
@ -562,6 +578,10 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CompositorOGL* compositorOGL = mCompositor->AsCompositorOGL();
|
||||||
|
bool canUseWebRenderSolid =
|
||||||
|
gfxPrefs::WebRenderEnabled() && compositorOGL && aTransform.Is2D();
|
||||||
|
|
||||||
if (aBackgroundColor) {
|
if (aBackgroundColor) {
|
||||||
nsIntRegion backgroundRegion = compositeRegion;
|
nsIntRegion backgroundRegion = compositeRegion;
|
||||||
backgroundRegion.ScaleRoundOut(resolution, resolution);
|
backgroundRegion.ScaleRoundOut(resolution, resolution);
|
||||||
|
|
@ -570,7 +590,12 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
||||||
for (auto iter = backgroundRegion.RectIter(); !iter.Done(); iter.Next()) {
|
for (auto iter = backgroundRegion.RectIter(); !iter.Done(); iter.Next()) {
|
||||||
const IntRect& rect = iter.Get();
|
const IntRect& rect = iter.Get();
|
||||||
Rect graphicsRect(rect.x, rect.y, rect.width, rect.height);
|
Rect graphicsRect(rect.x, rect.y, rect.width, rect.height);
|
||||||
mCompositor->DrawQuad(graphicsRect, aClipRect, effect, 1.0, aTransform);
|
if (!canUseWebRenderSolid ||
|
||||||
|
!compositorOGL->DrawWebRenderRect(
|
||||||
|
graphicsRect, *aBackgroundColor, 1.0, aTransform, aClipRect)) {
|
||||||
|
mCompositor->DrawQuad(graphicsRect, aClipRect, effect, 1.0,
|
||||||
|
aTransform);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,9 @@ CompositorOGL::CompositorOGL(CompositorBridgeParent* aParent,
|
||||||
, mWidgetSize(-1, -1)
|
, mWidgetSize(-1, -1)
|
||||||
, mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
|
, mSurfaceSize(aSurfaceWidth, aSurfaceHeight)
|
||||||
, mWebRenderContext(nullptr)
|
, mWebRenderContext(nullptr)
|
||||||
|
, mWebRenderViewport(0, 0, 0, 0)
|
||||||
|
, mWebRenderSceneHasCommands(false)
|
||||||
|
, mNextWebRenderImageKey(1)
|
||||||
, mHasBGRA(0)
|
, mHasBGRA(0)
|
||||||
, mUseExternalSurfaceSize(aUseExternalSurfaceSize)
|
, mUseExternalSurfaceSize(aUseExternalSurfaceSize)
|
||||||
, mFrameInProgress(false)
|
, mFrameInProgress(false)
|
||||||
|
|
@ -170,6 +173,8 @@ CompositorOGL::CleanupResources()
|
||||||
wr_context_destroy(mWebRenderContext);
|
wr_context_destroy(mWebRenderContext);
|
||||||
mWebRenderContext = nullptr;
|
mWebRenderContext = nullptr;
|
||||||
}
|
}
|
||||||
|
mWebRenderSceneHasCommands = false;
|
||||||
|
mWebRenderSceneImageSources.Clear();
|
||||||
|
|
||||||
if (!mGLContext)
|
if (!mGLContext)
|
||||||
return;
|
return;
|
||||||
|
|
@ -651,6 +656,22 @@ CompositorOGL::BeginFrame(const nsIntRegion& aInvalidRegion,
|
||||||
|
|
||||||
// We're about to actually draw a frame.
|
// We're about to actually draw a frame.
|
||||||
mFrameInProgress = true;
|
mFrameInProgress = true;
|
||||||
|
mWebRenderViewport = rect;
|
||||||
|
mWebRenderSceneHasCommands = false;
|
||||||
|
mWebRenderSceneImageSources.Clear();
|
||||||
|
mNextWebRenderImageKey = 1;
|
||||||
|
if (gfxPrefs::WebRenderEnabled()) {
|
||||||
|
if (!mWebRenderContext) {
|
||||||
|
mWebRenderContext = wr_context_create(16);
|
||||||
|
}
|
||||||
|
if (mWebRenderContext) {
|
||||||
|
wr_context_clear(mWebRenderContext);
|
||||||
|
wr_context_clear_images(mWebRenderContext);
|
||||||
|
wr_context_set_viewport(mWebRenderContext,
|
||||||
|
wr_rect{ Float(rect.x), Float(rect.y),
|
||||||
|
Float(rect.width), Float(rect.height) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the widget size changed, we have to force a MakeCurrent
|
// If the widget size changed, we have to force a MakeCurrent
|
||||||
// to make sure that GL sees the updated widget size.
|
// to make sure that GL sees the updated widget size.
|
||||||
|
|
@ -1002,7 +1023,10 @@ CompositorOGL::DrawTriangle(const gfx::TexturedTriangle& aTriangle,
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CompositorOGL::DrawWebRenderContext(wr_context* aContext,
|
CompositorOGL::DrawWebRenderContext(wr_context* aContext,
|
||||||
const IntRect& aClipRect)
|
const IntRect& aClipRect,
|
||||||
|
TextureSource* aImageSource,
|
||||||
|
uint32_t aImageKey,
|
||||||
|
bool aImagePremultiplied)
|
||||||
{
|
{
|
||||||
if (!aContext) {
|
if (!aContext) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1010,7 +1034,13 @@ CompositorOGL::DrawWebRenderContext(wr_context* aContext,
|
||||||
|
|
||||||
const wr_frame* frame = wr_context_build_frame(aContext);
|
const wr_frame* frame = wr_context_build_frame(aContext);
|
||||||
if (frame) {
|
if (frame) {
|
||||||
DrawWebRenderFrame(*frame, aClipRect);
|
WebRenderImageSource imageSource;
|
||||||
|
imageSource.mSource = aImageSource;
|
||||||
|
imageSource.mKey = aImageKey;
|
||||||
|
imageSource.mPremultiplied = aImagePremultiplied;
|
||||||
|
DrawWebRenderFrame(*frame, aClipRect,
|
||||||
|
aImageSource && aImageKey ? &imageSource : nullptr,
|
||||||
|
aImageSource && aImageKey ? 1 : 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -1023,42 +1053,169 @@ CompositorOGL::DrawWebRenderRect(const Rect& aRect,
|
||||||
const Matrix4x4& aTransform,
|
const Matrix4x4& aTransform,
|
||||||
const IntRect& aClipRect)
|
const IntRect& aClipRect)
|
||||||
{
|
{
|
||||||
if (!mFrameInProgress || aClipRect.IsEmpty() || !aTransform.Is2D()) {
|
if (!gfxPrefs::WebRenderEnabled() || !mFrameInProgress ||
|
||||||
|
aClipRect.IsEmpty() || !aTransform.Is2D()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!mWebRenderContext) {
|
if (!mWebRenderContext) {
|
||||||
mWebRenderContext = wr_context_create(8);
|
mWebRenderContext = wr_context_create(16);
|
||||||
}
|
}
|
||||||
if (!mWebRenderContext) {
|
if (!mWebRenderContext) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
wr_context_clear(mWebRenderContext);
|
|
||||||
wr_context_set_viewport(mWebRenderContext,
|
wr_context_set_viewport(mWebRenderContext,
|
||||||
wr_rect{ Float(aClipRect.x), Float(aClipRect.y),
|
wr_rect{ Float(mWebRenderViewport.x),
|
||||||
Float(aClipRect.width), Float(aClipRect.height) });
|
Float(mWebRenderViewport.y),
|
||||||
|
Float(mWebRenderViewport.width),
|
||||||
|
Float(mWebRenderViewport.height) });
|
||||||
Matrix transform = aTransform.As2D();
|
Matrix transform = aTransform.As2D();
|
||||||
wr_context_set_transform(mWebRenderContext,
|
wr_context_set_transform(mWebRenderContext,
|
||||||
wr_transform{ transform._11, transform._12,
|
wr_transform{ transform._11, transform._12,
|
||||||
transform._21, transform._22,
|
transform._21, transform._22,
|
||||||
transform._31, transform._32 });
|
transform._31, transform._32 });
|
||||||
wr_context_set_opacity(mWebRenderContext, aOpacity);
|
wr_context_set_opacity(mWebRenderContext, aOpacity);
|
||||||
|
if (!wr_context_begin_transaction(mWebRenderContext)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wr_display_list_push_clip(
|
||||||
|
mWebRenderContext,
|
||||||
|
wr_rect{ Float(aClipRect.x), Float(aClipRect.y),
|
||||||
|
Float(aClipRect.width), Float(aClipRect.height) })) {
|
||||||
|
wr_context_abort_transaction(mWebRenderContext);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!wr_display_list_push_rect(mWebRenderContext,
|
if (!wr_display_list_push_rect(mWebRenderContext,
|
||||||
wr_rect{ aRect.x, aRect.y,
|
wr_rect{ aRect.x, aRect.y,
|
||||||
aRect.width, aRect.height },
|
aRect.width, aRect.height },
|
||||||
wr_color{ aColor.r, aColor.g,
|
wr_color{ aColor.r, aColor.g,
|
||||||
aColor.b, aColor.a })) {
|
aColor.b, aColor.a })) {
|
||||||
|
wr_context_abort_transaction(mWebRenderContext);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wr_display_list_pop_clip(mWebRenderContext);
|
||||||
|
if (!wr_context_commit_transaction(mWebRenderContext)) {
|
||||||
|
wr_context_abort_transaction(mWebRenderContext);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool drawn = DrawWebRenderContext(mWebRenderContext, aClipRect);
|
mWebRenderSceneHasCommands = true;
|
||||||
wr_context_clear(mWebRenderContext);
|
return true;
|
||||||
return drawn;
|
}
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
CompositorOGL::RegisterWebRenderImage(TextureSource* aImageSource,
|
||||||
|
bool aPremultiplied)
|
||||||
|
{
|
||||||
|
IntSize imageSize;
|
||||||
|
uint32_t key;
|
||||||
|
|
||||||
|
for (const WebRenderImageSource& image : mWebRenderSceneImageSources) {
|
||||||
|
if (image.mSource == aImageSource &&
|
||||||
|
image.mPremultiplied == aPremultiplied) {
|
||||||
|
return image.mKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aImageSource) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
imageSize = aImageSource->GetSize();
|
||||||
|
if (imageSize.width <= 0 || imageSize.height <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
key = mNextWebRenderImageKey++;
|
||||||
|
if (!key) {
|
||||||
|
key = mNextWebRenderImageKey++;
|
||||||
|
}
|
||||||
|
if (!wr_context_register_image(mWebRenderContext, key,
|
||||||
|
uint32_t(imageSize.width),
|
||||||
|
uint32_t(imageSize.height))) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WebRenderImageSource* image =
|
||||||
|
mWebRenderSceneImageSources.AppendElement();
|
||||||
|
image->mSource = aImageSource;
|
||||||
|
image->mKey = key;
|
||||||
|
image->mPremultiplied = aPremultiplied;
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CompositorOGL::DrawWebRenderImage(TextureSource* aImageSource,
|
||||||
|
const Rect& aRect,
|
||||||
|
const Rect& aTexRect,
|
||||||
|
Float aOpacity,
|
||||||
|
const Matrix4x4& aTransform,
|
||||||
|
const IntRect& aClipRect,
|
||||||
|
bool aPremultiplied)
|
||||||
|
{
|
||||||
|
if (!gfxPrefs::WebRenderEnabled() || !aImageSource ||
|
||||||
|
!mFrameInProgress || aClipRect.IsEmpty() ||
|
||||||
|
!aTransform.Is2D()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (aImageSource->AsSourceOGL() == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!mWebRenderContext) {
|
||||||
|
mWebRenderContext = wr_context_create(16);
|
||||||
|
}
|
||||||
|
if (!mWebRenderContext) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
wr_context_set_viewport(mWebRenderContext,
|
||||||
|
wr_rect{ Float(mWebRenderViewport.x),
|
||||||
|
Float(mWebRenderViewport.y),
|
||||||
|
Float(mWebRenderViewport.width),
|
||||||
|
Float(mWebRenderViewport.height) });
|
||||||
|
Matrix transform = aTransform.As2D();
|
||||||
|
wr_context_set_transform(mWebRenderContext,
|
||||||
|
wr_transform{ transform._11, transform._12,
|
||||||
|
transform._21, transform._22,
|
||||||
|
transform._31, transform._32 });
|
||||||
|
wr_context_set_opacity(mWebRenderContext, aOpacity);
|
||||||
|
uint32_t imageKey = RegisterWebRenderImage(aImageSource, aPremultiplied);
|
||||||
|
if (!imageKey) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wr_context_begin_transaction(mWebRenderContext)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wr_display_list_push_clip(
|
||||||
|
mWebRenderContext,
|
||||||
|
wr_rect{ Float(aClipRect.x), Float(aClipRect.y),
|
||||||
|
Float(aClipRect.width), Float(aClipRect.height) })) {
|
||||||
|
wr_context_abort_transaction(mWebRenderContext);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wr_display_list_push_image(
|
||||||
|
mWebRenderContext,
|
||||||
|
wr_rect{ aRect.x, aRect.y, aRect.width, aRect.height },
|
||||||
|
imageKey, wr_rect{ aTexRect.x, aTexRect.y,
|
||||||
|
aTexRect.width, aTexRect.height },
|
||||||
|
wr_color{ 1, 1, 1, 1 })) {
|
||||||
|
wr_context_abort_transaction(mWebRenderContext);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
wr_display_list_pop_clip(mWebRenderContext);
|
||||||
|
if (!wr_context_commit_transaction(mWebRenderContext)) {
|
||||||
|
wr_context_abort_transaction(mWebRenderContext);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mWebRenderSceneHasCommands = true;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CompositorOGL::DrawWebRenderFrame(const wr_frame& aFrame,
|
CompositorOGL::DrawWebRenderFrame(const wr_frame& aFrame,
|
||||||
const IntRect& aClipRect)
|
const IntRect& aClipRect,
|
||||||
|
const WebRenderImageSource* aImageSources,
|
||||||
|
size_t aImageSourceCount)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mFrameInProgress, "frame not started");
|
MOZ_ASSERT(mFrameInProgress, "frame not started");
|
||||||
MOZ_ASSERT(mCurrentRenderTarget, "No destination");
|
MOZ_ASSERT(mCurrentRenderTarget, "No destination");
|
||||||
|
|
@ -1070,21 +1227,10 @@ CompositorOGL::DrawWebRenderFrame(const wr_frame& aFrame,
|
||||||
|
|
||||||
MakeCurrent();
|
MakeCurrent();
|
||||||
|
|
||||||
// This first adapter handles solid rectangles. It deliberately reuses the
|
|
||||||
// compositor's existing four-rect uniform and triangle VBO path, so the
|
|
||||||
// retained C display list is submitted to the GPU without a CPU raster pass.
|
|
||||||
EffectSolidColor effect(Color(0, 0, 0, 0));
|
|
||||||
ShaderConfigOGL config = GetShaderConfigFor(&effect);
|
|
||||||
ShaderProgramOGL* program = GetShaderProgramFor(config);
|
|
||||||
if (!program) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
IntPoint offset = mCurrentRenderTarget->GetOrigin();
|
IntPoint offset = mCurrentRenderTarget->GetOrigin();
|
||||||
ActivateProgram(program);
|
EffectSolidColor solidEffect(Color(0, 0, 0, 0));
|
||||||
program->SetProjectionMatrix(mProjMatrix);
|
ShaderConfigOGL solidConfig = GetShaderConfigFor(&solidEffect);
|
||||||
program->SetLayerTransform(Matrix4x4());
|
ShaderProgramOGL* solidProgram = GetShaderProgramFor(solidConfig);
|
||||||
program->SetRenderOffset(offset.x, offset.y);
|
|
||||||
|
|
||||||
ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
|
ScopedGLState scopedScissorTestState(mGLContext, LOCAL_GL_SCISSOR_TEST, true);
|
||||||
ScopedScissorRect autoScissorRect(mGLContext,
|
ScopedScissorRect autoScissorRect(mGLContext,
|
||||||
|
|
@ -1115,15 +1261,71 @@ CompositorOGL::DrawWebRenderFrame(const wr_frame& aFrame,
|
||||||
mGLContext, batchClip.x, FlipY(batchClip.y + batchClip.height),
|
mGLContext, batchClip.x, FlipY(batchClip.y + batchClip.height),
|
||||||
batchClip.width, batchClip.height);
|
batchClip.width, batchClip.height);
|
||||||
|
|
||||||
|
ShaderProgramOGL* program = solidProgram;
|
||||||
|
TextureSourceOGL* imageSource = nullptr;
|
||||||
|
bool imagePremultiplied = true;
|
||||||
|
gfx::Rect textureRects[4] = {};
|
||||||
|
if (batch.kind == WR_PRIMITIVE_IMAGE) {
|
||||||
|
TextureSource* source = nullptr;
|
||||||
|
for (size_t sourceIndex = 0; sourceIndex < aImageSourceCount;
|
||||||
|
++sourceIndex) {
|
||||||
|
if (aImageSources[sourceIndex].mKey == batch.image_key) {
|
||||||
|
source = aImageSources[sourceIndex].mSource;
|
||||||
|
imagePremultiplied = aImageSources[sourceIndex].mPremultiplied;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!source) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
imageSource = source->AsSourceOGL();
|
||||||
|
if (!imageSource) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
EffectRGB imageEffect(source, imagePremultiplied,
|
||||||
|
SamplingFilter::LINEAR);
|
||||||
|
ShaderConfigOGL imageConfig = GetShaderConfigFor(&imageEffect);
|
||||||
|
imageConfig.SetTextureTint(true);
|
||||||
|
imageConfig.SetOpacity(batch.color.a != 1.0f);
|
||||||
|
program = GetShaderProgramFor(imageConfig);
|
||||||
|
if (!program) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ActivateProgram(program);
|
||||||
|
imageSource->BindTexture(LOCAL_GL_TEXTURE0, SamplingFilter::LINEAR);
|
||||||
|
program->SetTextureUnit(0);
|
||||||
|
program->SetTextureTransform(imageSource->GetTextureTransform());
|
||||||
|
if (imageConfig.mFeatures & ENABLE_TEXTURE_RECT) {
|
||||||
|
program->SetTexCoordMultiplier(imageSource->GetSize().width,
|
||||||
|
imageSource->GetSize().height);
|
||||||
|
}
|
||||||
|
if (batch.color.a != 1.0f) {
|
||||||
|
program->SetLayerOpacity(batch.color.a);
|
||||||
|
}
|
||||||
|
program->SetTextureTint(Color(batch.color.r, batch.color.g,
|
||||||
|
batch.color.b, 1.0f));
|
||||||
|
} else {
|
||||||
|
if (!program) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ActivateProgram(program);
|
||||||
|
SetBlendMode(gl(), CompositionOp::OP_OVER);
|
||||||
|
program->SetRenderColor(Color(batch.color.r, batch.color.g,
|
||||||
|
batch.color.b, batch.color.a));
|
||||||
|
}
|
||||||
|
|
||||||
|
program->SetProjectionMatrix(mProjMatrix);
|
||||||
program->SetLayerTransform(Matrix4x4::From2D(
|
program->SetLayerTransform(Matrix4x4::From2D(
|
||||||
Matrix(batch.transform.m11, batch.transform.m12,
|
Matrix(batch.transform.m11, batch.transform.m12,
|
||||||
batch.transform.m21, batch.transform.m22,
|
batch.transform.m21, batch.transform.m22,
|
||||||
batch.transform.m31, batch.transform.m32)));
|
batch.transform.m31, batch.transform.m32)));
|
||||||
|
program->SetRenderOffset(offset.x, offset.y);
|
||||||
|
if (imageSource) {
|
||||||
|
SetBlendMode(gl(), CompositionOp::OP_OVER, imagePremultiplied);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t remaining = batch.quad_count;
|
uint32_t remaining = batch.quad_count;
|
||||||
uint32_t quadIndex = batch.first_quad;
|
uint32_t quadIndex = batch.first_quad;
|
||||||
program->SetRenderColor(Color(batch.color.r, batch.color.g,
|
|
||||||
batch.color.b, batch.color.a));
|
|
||||||
|
|
||||||
while (remaining) {
|
while (remaining) {
|
||||||
Rect rects[4] = {};
|
Rect rects[4] = {};
|
||||||
|
|
@ -1132,14 +1334,38 @@ CompositorOGL::DrawWebRenderFrame(const wr_frame& aFrame,
|
||||||
const wr_gpu_quad& quad = aFrame.quads[quadIndex + i];
|
const wr_gpu_quad& quad = aFrame.quads[quadIndex + i];
|
||||||
rects[i] = Rect(quad.rect.x, quad.rect.y,
|
rects[i] = Rect(quad.rect.x, quad.rect.y,
|
||||||
quad.rect.width, quad.rect.height);
|
quad.rect.width, quad.rect.height);
|
||||||
|
if (imageSource) {
|
||||||
|
textureRects[i] = Rect(quad.tex_rect.x, quad.tex_rect.y,
|
||||||
|
quad.tex_rect.width, quad.tex_rect.height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
BindAndDrawQuads(program, count, rects, nullptr);
|
BindAndDrawQuads(program, count, rects,
|
||||||
|
imageSource ? textureRects : nullptr);
|
||||||
quadIndex += count;
|
quadIndex += count;
|
||||||
remaining -= count;
|
remaining -= count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CompositorOGL::FlushWebRenderScene()
|
||||||
|
{
|
||||||
|
if (!mWebRenderSceneHasCommands || !mWebRenderContext ||
|
||||||
|
!mFrameInProgress) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wr_frame* frame = wr_context_build_frame(mWebRenderContext);
|
||||||
|
if (frame) {
|
||||||
|
DrawWebRenderFrame(*frame, mWebRenderViewport,
|
||||||
|
mWebRenderSceneImageSources.Elements(),
|
||||||
|
mWebRenderSceneImageSources.Length());
|
||||||
|
}
|
||||||
|
wr_context_clear(mWebRenderContext);
|
||||||
|
mWebRenderSceneHasCommands = false;
|
||||||
|
mWebRenderSceneImageSources.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Geometry>
|
template<typename Geometry>
|
||||||
void
|
void
|
||||||
CompositorOGL::DrawGeometry(const Geometry& aGeometry,
|
CompositorOGL::DrawGeometry(const Geometry& aGeometry,
|
||||||
|
|
@ -1152,6 +1378,8 @@ CompositorOGL::DrawGeometry(const Geometry& aGeometry,
|
||||||
MOZ_ASSERT(mFrameInProgress, "frame not started");
|
MOZ_ASSERT(mFrameInProgress, "frame not started");
|
||||||
MOZ_ASSERT(mCurrentRenderTarget, "No destination");
|
MOZ_ASSERT(mCurrentRenderTarget, "No destination");
|
||||||
|
|
||||||
|
FlushWebRenderScene();
|
||||||
|
|
||||||
MakeCurrent();
|
MakeCurrent();
|
||||||
|
|
||||||
IntPoint offset = mCurrentRenderTarget->GetOrigin();
|
IntPoint offset = mCurrentRenderTarget->GetOrigin();
|
||||||
|
|
@ -1720,6 +1948,8 @@ CompositorOGL::EndFrame()
|
||||||
|
|
||||||
MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
|
MOZ_ASSERT(mCurrentRenderTarget == mWindowRenderTarget, "Rendering target not properly restored");
|
||||||
|
|
||||||
|
FlushWebRenderScene();
|
||||||
|
|
||||||
#ifdef MOZ_DUMP_PAINTING
|
#ifdef MOZ_DUMP_PAINTING
|
||||||
if (gfxEnv::DumpCompositorTextures()) {
|
if (gfxEnv::DumpCompositorTextures()) {
|
||||||
LayoutDeviceIntSize size;
|
LayoutDeviceIntSize size;
|
||||||
|
|
@ -1773,6 +2003,7 @@ void
|
||||||
CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
|
CompositorOGL::EndFrameForExternalComposition(const gfx::Matrix& aTransform)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!mTarget);
|
MOZ_ASSERT(!mTarget);
|
||||||
|
FlushWebRenderScene();
|
||||||
if (mTexturePool) {
|
if (mTexturePool) {
|
||||||
mTexturePool->EndFrame();
|
mTexturePool->EndFrame();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@
|
||||||
#include "nsXULAppAPI.h" // for XRE_GetProcessType
|
#include "nsXULAppAPI.h" // for XRE_GetProcessType
|
||||||
#include "nscore.h" // for NS_IMETHOD
|
#include "nscore.h" // for NS_IMETHOD
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
class nsIWidget;
|
class nsIWidget;
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
@ -169,6 +171,12 @@ protected:
|
||||||
public:
|
public:
|
||||||
virtual CompositorOGL* AsCompositorOGL() override { return this; }
|
virtual CompositorOGL* AsCompositorOGL() override { return this; }
|
||||||
|
|
||||||
|
struct WebRenderImageSource {
|
||||||
|
RefPtr<TextureSource> mSource;
|
||||||
|
uint32_t mKey;
|
||||||
|
bool mPremultiplied;
|
||||||
|
};
|
||||||
|
|
||||||
virtual already_AddRefed<DataTextureSource>
|
virtual already_AddRefed<DataTextureSource>
|
||||||
CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) override;
|
CreateDataTextureSource(TextureFlags aFlags = TextureFlags::NO_FLAGS) override;
|
||||||
|
|
||||||
|
|
@ -214,14 +222,29 @@ public:
|
||||||
|
|
||||||
// Consume solid retained-display-list quads through the existing GPU path.
|
// Consume solid retained-display-list quads through the existing GPU path.
|
||||||
bool DrawWebRenderContext(wr_context* aContext,
|
bool DrawWebRenderContext(wr_context* aContext,
|
||||||
const gfx::IntRect& aClipRect);
|
const gfx::IntRect& aClipRect,
|
||||||
|
TextureSource* aImageSource = nullptr,
|
||||||
|
uint32_t aImageKey = 0,
|
||||||
|
bool aImagePremultiplied = true);
|
||||||
bool DrawWebRenderRect(const gfx::Rect& aRect,
|
bool DrawWebRenderRect(const gfx::Rect& aRect,
|
||||||
const gfx::Color& aColor,
|
const gfx::Color& aColor,
|
||||||
gfx::Float aOpacity,
|
gfx::Float aOpacity,
|
||||||
const gfx::Matrix4x4& aTransform,
|
const gfx::Matrix4x4& aTransform,
|
||||||
const gfx::IntRect& aClipRect);
|
const gfx::IntRect& aClipRect);
|
||||||
|
bool DrawWebRenderImage(TextureSource* aImageSource,
|
||||||
|
const gfx::Rect& aRect,
|
||||||
|
const gfx::Rect& aTexRect,
|
||||||
|
gfx::Float aOpacity,
|
||||||
|
const gfx::Matrix4x4& aTransform,
|
||||||
|
const gfx::IntRect& aClipRect,
|
||||||
|
bool aPremultiplied);
|
||||||
void DrawWebRenderFrame(const wr_frame& aFrame,
|
void DrawWebRenderFrame(const wr_frame& aFrame,
|
||||||
const gfx::IntRect& aClipRect);
|
const gfx::IntRect& aClipRect,
|
||||||
|
const WebRenderImageSource* aImageSources,
|
||||||
|
size_t aImageSourceCount);
|
||||||
|
void FlushWebRenderScene();
|
||||||
|
uint32_t RegisterWebRenderImage(TextureSource* aImageSource,
|
||||||
|
bool aPremultiplied);
|
||||||
|
|
||||||
virtual void EndFrame() override;
|
virtual void EndFrame() override;
|
||||||
virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) override;
|
virtual void EndFrameForExternalComposition(const gfx::Matrix& aTransform) override;
|
||||||
|
|
@ -340,6 +363,10 @@ private:
|
||||||
/** Currently bound render target */
|
/** Currently bound render target */
|
||||||
RefPtr<CompositingRenderTargetOGL> mCurrentRenderTarget;
|
RefPtr<CompositingRenderTargetOGL> mCurrentRenderTarget;
|
||||||
wr_context* mWebRenderContext;
|
wr_context* mWebRenderContext;
|
||||||
|
gfx::IntRect mWebRenderViewport;
|
||||||
|
bool mWebRenderSceneHasCommands;
|
||||||
|
nsTArray<WebRenderImageSource> mWebRenderSceneImageSources;
|
||||||
|
uint32_t mNextWebRenderImageKey;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
CompositingRenderTargetOGL* mWindowRenderTarget;
|
CompositingRenderTargetOGL* mWindowRenderTarget;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ AddUniforms(ProgramProfileOGL& aProfile)
|
||||||
"uViewportSize",
|
"uViewportSize",
|
||||||
"uVisibleCenter",
|
"uVisibleCenter",
|
||||||
"uYuvColorMatrix",
|
"uYuvColorMatrix",
|
||||||
|
"uTextureTint",
|
||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -75,6 +76,12 @@ ShaderConfigOGL::SetRenderColor(bool aEnabled)
|
||||||
SetFeature(ENABLE_RENDER_COLOR, aEnabled);
|
SetFeature(ENABLE_RENDER_COLOR, aEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ShaderConfigOGL::SetTextureTint(bool aEnabled)
|
||||||
|
{
|
||||||
|
SetFeature(ENABLE_TEXTURE_TINT, aEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ShaderConfigOGL::SetTextureTarget(GLenum aTarget)
|
ShaderConfigOGL::SetTextureTarget(GLenum aTarget)
|
||||||
{
|
{
|
||||||
|
|
@ -351,6 +358,9 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||||
if (aConfig.mFeatures & ENABLE_OPACITY) {
|
if (aConfig.mFeatures & ENABLE_OPACITY) {
|
||||||
fs << "uniform COLOR_PRECISION float uLayerOpacity;" << endl;
|
fs << "uniform COLOR_PRECISION float uLayerOpacity;" << endl;
|
||||||
}
|
}
|
||||||
|
if (aConfig.mFeatures & ENABLE_TEXTURE_TINT) {
|
||||||
|
fs << "uniform COLOR_PRECISION vec4 uTextureTint;" << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (BlendOpIsMixBlendMode(blendOp)) {
|
if (BlendOpIsMixBlendMode(blendOp)) {
|
||||||
fs << "varying vec2 vBackdropCoord;" << endl;
|
fs << "varying vec2 vBackdropCoord;" << endl;
|
||||||
|
|
@ -506,6 +516,9 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig)
|
||||||
if (aConfig.mFeatures & ENABLE_OPACITY) {
|
if (aConfig.mFeatures & ENABLE_OPACITY) {
|
||||||
fs << " color *= uLayerOpacity;" << endl;
|
fs << " color *= uLayerOpacity;" << endl;
|
||||||
}
|
}
|
||||||
|
if (aConfig.mFeatures & ENABLE_TEXTURE_TINT) {
|
||||||
|
fs << " color *= uTextureTint;" << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (aConfig.mFeatures & ENABLE_DEAA) {
|
if (aConfig.mFeatures & ENABLE_DEAA) {
|
||||||
// Calculate the sub-pixel coverage of the pixel and modulate its opacity
|
// Calculate the sub-pixel coverage of the pixel and modulate its opacity
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,8 @@ enum ShaderFeatures {
|
||||||
ENABLE_MASK=0x800,
|
ENABLE_MASK=0x800,
|
||||||
ENABLE_NO_PREMUL_ALPHA=0x1000,
|
ENABLE_NO_PREMUL_ALPHA=0x1000,
|
||||||
ENABLE_DEAA=0x2000,
|
ENABLE_DEAA=0x2000,
|
||||||
ENABLE_DYNAMIC_GEOMETRY=0x4000
|
ENABLE_DYNAMIC_GEOMETRY=0x4000,
|
||||||
|
ENABLE_TEXTURE_TINT=0x8000
|
||||||
};
|
};
|
||||||
|
|
||||||
class KnownUniform {
|
class KnownUniform {
|
||||||
|
|
@ -83,6 +84,7 @@ public:
|
||||||
ViewportSize,
|
ViewportSize,
|
||||||
VisibleCenter,
|
VisibleCenter,
|
||||||
YuvColorMatrix,
|
YuvColorMatrix,
|
||||||
|
TextureTint,
|
||||||
|
|
||||||
KnownUniformCount
|
KnownUniformCount
|
||||||
};
|
};
|
||||||
|
|
@ -218,6 +220,7 @@ public:
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void SetRenderColor(bool aEnabled);
|
void SetRenderColor(bool aEnabled);
|
||||||
|
void SetTextureTint(bool aEnabled);
|
||||||
void SetTextureTarget(GLenum aTarget);
|
void SetTextureTarget(GLenum aTarget);
|
||||||
void SetRBSwap(bool aEnabled);
|
void SetRBSwap(bool aEnabled);
|
||||||
void SetNoAlpha(bool aEnabled);
|
void SetNoAlpha(bool aEnabled);
|
||||||
|
|
@ -463,6 +466,10 @@ public:
|
||||||
SetUniform(KnownUniform::RenderColor, aColor);
|
SetUniform(KnownUniform::RenderColor, aColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetTextureTint(const gfx::Color& aColor) {
|
||||||
|
SetUniform(KnownUniform::TextureTint, aColor);
|
||||||
|
}
|
||||||
|
|
||||||
void SetColorMatrix(const gfx::Matrix5x4& aColorMatrix)
|
void SetColorMatrix(const gfx::Matrix5x4& aColorMatrix)
|
||||||
{
|
{
|
||||||
SetMatrixUniform(KnownUniform::ColorMatrix, &aColorMatrix._11);
|
SetMatrixUniform(KnownUniform::ColorMatrix, &aColorMatrix._11);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,14 @@ EXPORTS.mozilla.gfx += [
|
||||||
]
|
]
|
||||||
|
|
||||||
SOURCES += [
|
SOURCES += [
|
||||||
'webrender.c',
|
'wr_context.c',
|
||||||
|
'wr_display_list.c',
|
||||||
|
'wr_frame.c',
|
||||||
|
'wr_frame_packet.c',
|
||||||
|
'wr_retained.c',
|
||||||
|
'wr_util.c',
|
||||||
]
|
]
|
||||||
|
|
||||||
FINAL_LIBRARY = 'xul'
|
FINAL_LIBRARY = 'xul'
|
||||||
|
|
||||||
|
TEST_DIRS += ['tests']
|
||||||
|
|
|
||||||
5
gfx/wr/tests/moz.build
Normal file
5
gfx/wr/tests/moz.build
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||||
|
|
||||||
|
# This is a standalone C regression executable. It includes the C renderer
|
||||||
|
# implementation directly so it does not require another language's harness.
|
||||||
|
SimplePrograms(['webrender_test'], ext='.c')
|
||||||
274
gfx/wr/tests/webrender_test.c
Normal file
274
gfx/wr/tests/webrender_test.c
Normal file
|
|
@ -0,0 +1,274 @@
|
||||||
|
#include "../wr_util.c"
|
||||||
|
#include "../wr_context.c"
|
||||||
|
#include "../wr_display_list.c"
|
||||||
|
#include "../wr_frame.c"
|
||||||
|
#include "../wr_frame_packet.c"
|
||||||
|
#include "../wr_retained.c"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_retained_frame(void)
|
||||||
|
{
|
||||||
|
wr_context* context = wr_context_create(4);
|
||||||
|
const wr_frame* first;
|
||||||
|
const wr_frame* cached;
|
||||||
|
const wr_frame* culled;
|
||||||
|
|
||||||
|
assert(context);
|
||||||
|
wr_context_set_viewport(context, (wr_rect){ 0, 0, 100, 100 });
|
||||||
|
assert(wr_display_list_push_rect(context, (wr_rect){ 0, 0, 10, 10 },
|
||||||
|
(wr_color){ 1, 0, 0, 1 }));
|
||||||
|
first = wr_context_build_frame(context);
|
||||||
|
cached = wr_context_build_frame(context);
|
||||||
|
assert(first == cached);
|
||||||
|
assert(cached->quad_count == 1 && cached->batch_count == 1);
|
||||||
|
|
||||||
|
wr_context_set_viewport(context, (wr_rect){ 200, 200, 10, 10 });
|
||||||
|
culled = wr_context_build_frame(context);
|
||||||
|
assert(culled && culled->quad_count == 0);
|
||||||
|
wr_context_destroy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_stacking_and_image(void)
|
||||||
|
{
|
||||||
|
wr_context* context = wr_context_create(4);
|
||||||
|
const wr_frame* frame;
|
||||||
|
const wr_transform translate = { 1, 0, 0, 1, 20, 0 };
|
||||||
|
|
||||||
|
assert(context);
|
||||||
|
wr_context_set_viewport(context, (wr_rect){ 0, 0, 100, 100 });
|
||||||
|
assert(wr_context_register_image(context, 7, 64, 64));
|
||||||
|
assert(wr_display_list_push_stacking_context(context, translate, 0.5f));
|
||||||
|
assert(wr_display_list_push_clip(context, (wr_rect){ 15, 0, 30, 30 }));
|
||||||
|
assert(wr_display_list_push_rect(context, (wr_rect){ 0, 0, 10, 10 },
|
||||||
|
(wr_color){ 1, 0, 0, 1 }));
|
||||||
|
wr_display_list_pop_stacking_context(context);
|
||||||
|
assert(wr_display_list_push_image(
|
||||||
|
context, (wr_rect){ 30, 0, 20, 20 }, 7,
|
||||||
|
(wr_rect){ 0, 0, 0.5f, 0.5f }, (wr_color){ 0.25f, 0.5f, 0.75f, 1 }));
|
||||||
|
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 2 && frame->batch_count == 2);
|
||||||
|
assert(frame->quads[0].color.a == 0.5f);
|
||||||
|
assert(frame->batches[0].has_clip);
|
||||||
|
assert(frame->batches[0].transform.m31 == 20);
|
||||||
|
assert(frame->batches[1].kind == WR_PRIMITIVE_IMAGE);
|
||||||
|
assert(frame->batches[1].image_key == 7);
|
||||||
|
assert(frame->quads[1].color.r == 0.25f);
|
||||||
|
assert(frame->quads[1].color.g == 0.5f);
|
||||||
|
assert(frame->quads[1].color.b == 0.75f);
|
||||||
|
assert(frame->quads[1].tex_rect.width == 0.5f);
|
||||||
|
wr_context_unregister_image(context, 7);
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 1 && frame->batch_count == 1);
|
||||||
|
wr_context_clear(context);
|
||||||
|
assert(!wr_display_list_push_image(
|
||||||
|
context, (wr_rect){ 30, 0, 20, 20 }, 7,
|
||||||
|
(wr_rect){ 0, 0, 0.5f, 0.5f }, (wr_color){ 1, 1, 1, 1 }));
|
||||||
|
wr_context_destroy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_scene_transactions(void)
|
||||||
|
{
|
||||||
|
wr_context* context = wr_context_create(2);
|
||||||
|
const wr_frame* frame;
|
||||||
|
|
||||||
|
assert(context);
|
||||||
|
wr_context_set_viewport(context, (wr_rect){ 0, 0, 100, 100 });
|
||||||
|
assert(wr_display_list_push_rect(context, (wr_rect){ 0, 0, 10, 10 },
|
||||||
|
(wr_color){ 1, 0, 0, 1 }));
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 1);
|
||||||
|
|
||||||
|
assert(wr_context_begin_transaction(context));
|
||||||
|
assert(wr_display_list_push_rect(context, (wr_rect){ 20, 0, 10, 10 },
|
||||||
|
(wr_color){ 0, 1, 0, 1 }));
|
||||||
|
wr_context_abort_transaction(context);
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 1);
|
||||||
|
|
||||||
|
assert(wr_context_begin_transaction(context));
|
||||||
|
assert(wr_display_list_push_rect(context, (wr_rect){ 20, 0, 10, 10 },
|
||||||
|
(wr_color){ 0, 1, 0, 1 }));
|
||||||
|
assert(wr_context_begin_transaction(context));
|
||||||
|
assert(wr_display_list_push_rect(context, (wr_rect){ 40, 0, 10, 10 },
|
||||||
|
(wr_color){ 0, 0, 1, 1 }));
|
||||||
|
wr_context_abort_transaction(context);
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 2);
|
||||||
|
assert(wr_context_commit_transaction(context));
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 2);
|
||||||
|
|
||||||
|
assert(!wr_context_commit_transaction(context));
|
||||||
|
wr_context_destroy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_multiple_image_resources(void)
|
||||||
|
{
|
||||||
|
wr_context* context = wr_context_create(4);
|
||||||
|
const wr_frame* frame;
|
||||||
|
|
||||||
|
assert(context);
|
||||||
|
wr_context_set_viewport(context, (wr_rect){ 0, 0, 100, 100 });
|
||||||
|
assert(wr_context_register_image(context, 11, 32, 32));
|
||||||
|
assert(wr_context_register_image(context, 12, 64, 64));
|
||||||
|
assert(wr_display_list_push_image(
|
||||||
|
context, (wr_rect){ 0, 0, 20, 20 }, 11,
|
||||||
|
(wr_rect){ 0, 0, 1, 1 }, (wr_color){ 1, 1, 1, 1 }));
|
||||||
|
assert(wr_display_list_push_image(
|
||||||
|
context, (wr_rect){ 20, 0, 20, 20 }, 12,
|
||||||
|
(wr_rect){ 0, 0, 1, 1 }, (wr_color){ 1, 1, 1, 1 }));
|
||||||
|
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 2 && frame->batch_count == 2);
|
||||||
|
assert(frame->batches[0].image_key == 11);
|
||||||
|
assert(frame->batches[1].image_key == 12);
|
||||||
|
wr_context_clear_images(context);
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 0 && frame->batch_count == 0);
|
||||||
|
wr_context_destroy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_stable_item_updates(void)
|
||||||
|
{
|
||||||
|
wr_context* context = wr_context_create(4);
|
||||||
|
const wr_frame* frame;
|
||||||
|
const wr_transform identity = { 1, 0, 0, 1, 0, 0 };
|
||||||
|
wr_item_id item;
|
||||||
|
|
||||||
|
assert(context);
|
||||||
|
wr_context_set_viewport(context, (wr_rect){ 0, 0, 100, 100 });
|
||||||
|
item = wr_display_list_push_rect_with_id(
|
||||||
|
context, 42, (wr_rect){ 0, 0, 10, 10 }, (wr_color){ 1, 0, 0, 1 });
|
||||||
|
assert(item == 42);
|
||||||
|
assert(wr_display_list_push_rect_with_id(
|
||||||
|
context, 42, (wr_rect){ 20, 0, 10, 10 }, (wr_color){ 0, 1, 0, 1 }) == 0);
|
||||||
|
|
||||||
|
assert(wr_context_begin_transaction(context));
|
||||||
|
assert(wr_display_list_update_rect(
|
||||||
|
context, item, (wr_rect){ 20, 0, 10, 10 },
|
||||||
|
(wr_color){ 0, 1, 0, 1 }, identity));
|
||||||
|
wr_context_abort_transaction(context);
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 1);
|
||||||
|
assert(frame->quads[0].rect.x == 0);
|
||||||
|
|
||||||
|
assert(wr_context_begin_transaction(context));
|
||||||
|
assert(wr_display_list_update_rect(
|
||||||
|
context, item, (wr_rect){ 20, 0, 10, 10 },
|
||||||
|
(wr_color){ 0, 1, 0, 1 }, identity));
|
||||||
|
assert(wr_context_commit_transaction(context));
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 1);
|
||||||
|
assert(frame->quads[0].rect.x == 20);
|
||||||
|
assert(frame->quads[0].item_id == 42);
|
||||||
|
|
||||||
|
assert(wr_context_remove_item(context, item));
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 0);
|
||||||
|
wr_context_destroy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_opaque_occlusion(void)
|
||||||
|
{
|
||||||
|
wr_context* context = wr_context_create(2);
|
||||||
|
const wr_frame* frame;
|
||||||
|
|
||||||
|
assert(context);
|
||||||
|
wr_context_set_viewport(context, (wr_rect){ 0, 0, 100, 100 });
|
||||||
|
assert(wr_display_list_push_rect(
|
||||||
|
context, (wr_rect){ 0, 0, 20, 20 }, (wr_color){ 1, 0, 0, 1 }));
|
||||||
|
assert(wr_display_list_push_rect(
|
||||||
|
context, (wr_rect){ 0, 0, 20, 20 }, (wr_color){ 0, 0, 1, 1 }));
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 1 && frame->batch_count == 1);
|
||||||
|
assert(frame->quads[0].color.b == 1.0f);
|
||||||
|
wr_context_destroy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_gpu_tessellated_primitives(void)
|
||||||
|
{
|
||||||
|
wr_context* context = wr_context_create(64);
|
||||||
|
const wr_frame* frame;
|
||||||
|
|
||||||
|
assert(context);
|
||||||
|
wr_context_set_viewport(context, (wr_rect){ 0, 0, 100, 100 });
|
||||||
|
assert(wr_display_list_push_linear_gradient(
|
||||||
|
context, (wr_rect){ 0, 0, 40, 20 },
|
||||||
|
(wr_color){ 1, 0, 0, 1 }, (wr_color){ 0, 0, 1, 1 }, 1));
|
||||||
|
assert(wr_display_list_push_rounded_rect(
|
||||||
|
context, (wr_rect){ 0, 20, 40, 20 }, (wr_color){ 0, 1, 0, 1 }, 8));
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 48);
|
||||||
|
wr_context_destroy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_glyph_run(void)
|
||||||
|
{
|
||||||
|
wr_context* context = wr_context_create(4);
|
||||||
|
const wr_frame* frame;
|
||||||
|
const wr_glyph glyphs[2] = {
|
||||||
|
{ { 0, 0, 8, 12 }, { 0, 0, 0.25f, 1 } },
|
||||||
|
{ { 8, 0, 8, 12 }, { 0.25f, 0, 0.25f, 1 } }
|
||||||
|
};
|
||||||
|
|
||||||
|
assert(context);
|
||||||
|
wr_context_set_viewport(context, (wr_rect){ 0, 0, 100, 100 });
|
||||||
|
assert(wr_context_register_image(context, 21, 256, 256));
|
||||||
|
assert(wr_display_list_push_glyph_run(
|
||||||
|
context, 21, glyphs, 2, (wr_color){ 1, 1, 1, 1 }));
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
assert(frame && frame->quad_count == 2 && frame->batch_count == 1);
|
||||||
|
assert(frame->batches[0].kind == WR_PRIMITIVE_IMAGE);
|
||||||
|
wr_context_destroy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_frame_packet(void)
|
||||||
|
{
|
||||||
|
wr_context* context = wr_context_create(2);
|
||||||
|
const wr_frame* frame;
|
||||||
|
size_t packet_size;
|
||||||
|
unsigned char* packet;
|
||||||
|
wr_frame_packet_header header;
|
||||||
|
|
||||||
|
assert(context);
|
||||||
|
wr_context_set_viewport(context, (wr_rect){ 0, 0, 100, 100 });
|
||||||
|
assert(wr_display_list_push_rect(
|
||||||
|
context, (wr_rect){ 0, 0, 10, 10 }, (wr_color){ 1, 0, 0, 1 }));
|
||||||
|
frame = wr_context_build_frame(context);
|
||||||
|
packet_size = wr_frame_packet_size(frame);
|
||||||
|
assert(packet_size > sizeof(header));
|
||||||
|
packet = (unsigned char*)malloc(packet_size);
|
||||||
|
assert(packet);
|
||||||
|
assert(wr_frame_serialize(frame, packet, packet_size));
|
||||||
|
memcpy(&header, packet, sizeof(header));
|
||||||
|
assert(header.version == WR_FRAME_PACKET_VERSION);
|
||||||
|
assert(header.quad_count == 1 && header.batch_count == 1);
|
||||||
|
free(packet);
|
||||||
|
wr_context_destroy(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
test_retained_frame();
|
||||||
|
test_stacking_and_image();
|
||||||
|
test_scene_transactions();
|
||||||
|
test_multiple_image_resources();
|
||||||
|
test_stable_item_updates();
|
||||||
|
test_opaque_occlusion();
|
||||||
|
test_gpu_tessellated_primitives();
|
||||||
|
test_glyph_run();
|
||||||
|
test_frame_packet();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -1,447 +0,0 @@
|
||||||
#include "webrender.h"
|
|
||||||
|
|
||||||
#include <float.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
wr_rect rect;
|
|
||||||
wr_color color;
|
|
||||||
wr_transform transform;
|
|
||||||
wr_rect clip_rect;
|
|
||||||
uint8_t has_clip;
|
|
||||||
} wr_rect_command;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
wr_transform transform;
|
|
||||||
float opacity;
|
|
||||||
size_t clip_depth;
|
|
||||||
} wr_display_state;
|
|
||||||
|
|
||||||
struct wr_context {
|
|
||||||
wr_rect_command* commands;
|
|
||||||
size_t command_count;
|
|
||||||
size_t command_capacity;
|
|
||||||
|
|
||||||
wr_gpu_quad* quads;
|
|
||||||
size_t quad_count;
|
|
||||||
size_t quad_capacity;
|
|
||||||
|
|
||||||
wr_gpu_batch* batches;
|
|
||||||
size_t batch_count;
|
|
||||||
size_t batch_capacity;
|
|
||||||
|
|
||||||
wr_rect viewport;
|
|
||||||
wr_transform transform;
|
|
||||||
float opacity;
|
|
||||||
wr_rect* clip_stack;
|
|
||||||
size_t clip_depth;
|
|
||||||
size_t clip_capacity;
|
|
||||||
wr_display_state* state_stack;
|
|
||||||
size_t state_depth;
|
|
||||||
size_t state_capacity;
|
|
||||||
wr_frame frame;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
wr_size_mul_overflow(size_t a, size_t b)
|
|
||||||
{
|
|
||||||
return b != 0 && a > SIZE_MAX / b;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wr_reserve(void** data, size_t* capacity, size_t count, size_t element_size)
|
|
||||||
{
|
|
||||||
size_t new_capacity;
|
|
||||||
void* new_data;
|
|
||||||
|
|
||||||
if (count <= *capacity)
|
|
||||||
return 1;
|
|
||||||
if (element_size == 0 || wr_size_mul_overflow(count, element_size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
new_capacity = *capacity ? *capacity : 8;
|
|
||||||
while (new_capacity < count) {
|
|
||||||
if (new_capacity > SIZE_MAX / 2) {
|
|
||||||
new_capacity = count;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
new_capacity *= 2;
|
|
||||||
}
|
|
||||||
if (wr_size_mul_overflow(new_capacity, element_size))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
new_data = realloc(*data, new_capacity * element_size);
|
|
||||||
if (!new_data)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
*data = new_data;
|
|
||||||
*capacity = new_capacity;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wr_valid_rect(wr_rect rect)
|
|
||||||
{
|
|
||||||
return isfinite(rect.x) && isfinite(rect.y) &&
|
|
||||||
isfinite(rect.width) && isfinite(rect.height) &&
|
|
||||||
rect.width > 0.0f && rect.height > 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wr_valid_transform(wr_transform transform)
|
|
||||||
{
|
|
||||||
return isfinite(transform.m11) && isfinite(transform.m12) &&
|
|
||||||
isfinite(transform.m21) && isfinite(transform.m22) &&
|
|
||||||
isfinite(transform.m31) && isfinite(transform.m32);
|
|
||||||
}
|
|
||||||
|
|
||||||
static wr_transform
|
|
||||||
wr_identity_transform(void)
|
|
||||||
{
|
|
||||||
wr_transform transform = { 1, 0, 0, 1, 0, 0 };
|
|
||||||
return transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
static wr_transform
|
|
||||||
wr_multiply_transform(wr_transform a, wr_transform b)
|
|
||||||
{
|
|
||||||
wr_transform result;
|
|
||||||
result.m11 = a.m11 * b.m11 + a.m21 * b.m12;
|
|
||||||
result.m12 = a.m12 * b.m11 + a.m22 * b.m12;
|
|
||||||
result.m21 = a.m11 * b.m21 + a.m21 * b.m22;
|
|
||||||
result.m22 = a.m12 * b.m21 + a.m22 * b.m22;
|
|
||||||
result.m31 = a.m11 * b.m31 + a.m21 * b.m32 + a.m31;
|
|
||||||
result.m32 = a.m12 * b.m31 + a.m22 * b.m32 + a.m32;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static wr_rect
|
|
||||||
wr_empty_rect(void)
|
|
||||||
{
|
|
||||||
wr_rect rect = { 0, 0, 0, 0 };
|
|
||||||
return rect;
|
|
||||||
}
|
|
||||||
|
|
||||||
static float
|
|
||||||
wr_clamp01(float value)
|
|
||||||
{
|
|
||||||
if (value < 0.0f)
|
|
||||||
return 0.0f;
|
|
||||||
if (value > 1.0f)
|
|
||||||
return 1.0f;
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static wr_color
|
|
||||||
wr_normalize_color(wr_color color)
|
|
||||||
{
|
|
||||||
color.r = wr_clamp01(color.r);
|
|
||||||
color.g = wr_clamp01(color.g);
|
|
||||||
color.b = wr_clamp01(color.b);
|
|
||||||
color.a = wr_clamp01(color.a);
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wr_colors_equal(wr_color a, wr_color b)
|
|
||||||
{
|
|
||||||
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wr_rects_equal(wr_rect a, wr_rect b)
|
|
||||||
{
|
|
||||||
return a.x == b.x && a.y == b.y &&
|
|
||||||
a.width == b.width && a.height == b.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
wr_intersects(wr_rect a, wr_rect b)
|
|
||||||
{
|
|
||||||
return a.x < b.x + b.width && a.x + a.width > b.x &&
|
|
||||||
a.y < b.y + b.height && a.y + a.height > b.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
static wr_rect
|
|
||||||
wr_intersect_rect(wr_rect a, wr_rect b)
|
|
||||||
{
|
|
||||||
float left = a.x > b.x ? a.x : b.x;
|
|
||||||
float top = a.y > b.y ? a.y : b.y;
|
|
||||||
float right = a.x + a.width < b.x + b.width ?
|
|
||||||
a.x + a.width : b.x + b.width;
|
|
||||||
float bottom = a.y + a.height < b.y + b.height ?
|
|
||||||
a.y + a.height : b.y + b.height;
|
|
||||||
wr_rect result = { left, top, right - left, bottom - top };
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static wr_rect
|
|
||||||
wr_transform_bounds(wr_rect rect, wr_transform transform)
|
|
||||||
{
|
|
||||||
float x1 = rect.x * transform.m11 + rect.y * transform.m21 + transform.m31;
|
|
||||||
float y1 = rect.x * transform.m12 + rect.y * transform.m22 + transform.m32;
|
|
||||||
float x2 = (rect.x + rect.width) * transform.m11 +
|
|
||||||
rect.y * transform.m21 + transform.m31;
|
|
||||||
float y2 = (rect.x + rect.width) * transform.m12 +
|
|
||||||
rect.y * transform.m22 + transform.m32;
|
|
||||||
float x3 = rect.x * transform.m11 +
|
|
||||||
(rect.y + rect.height) * transform.m21 + transform.m31;
|
|
||||||
float y3 = rect.x * transform.m12 +
|
|
||||||
(rect.y + rect.height) * transform.m22 + transform.m32;
|
|
||||||
float x4 = (rect.x + rect.width) * transform.m11 +
|
|
||||||
(rect.y + rect.height) * transform.m21 + transform.m31;
|
|
||||||
float y4 = (rect.x + rect.width) * transform.m12 +
|
|
||||||
(rect.y + rect.height) * transform.m22 + transform.m32;
|
|
||||||
float left = fminf(fminf(x1, x2), fminf(x3, x4));
|
|
||||||
float right = fmaxf(fmaxf(x1, x2), fmaxf(x3, x4));
|
|
||||||
float top = fminf(fminf(y1, y2), fminf(y3, y4));
|
|
||||||
float bottom = fmaxf(fmaxf(y1, y2), fmaxf(y3, y4));
|
|
||||||
wr_rect result = { left, top, right - left, bottom - top };
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
wr_context*
|
|
||||||
wr_context_create(size_t initial_capacity)
|
|
||||||
{
|
|
||||||
wr_context* context = (wr_context*)calloc(1, sizeof(*context));
|
|
||||||
if (!context)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
context->viewport.x = -FLT_MAX;
|
|
||||||
context->viewport.y = -FLT_MAX;
|
|
||||||
context->viewport.width = FLT_MAX;
|
|
||||||
context->viewport.height = FLT_MAX;
|
|
||||||
context->transform = wr_identity_transform();
|
|
||||||
context->opacity = 1.0f;
|
|
||||||
|
|
||||||
if (initial_capacity &&
|
|
||||||
!wr_reserve((void**)&context->commands, &context->command_capacity,
|
|
||||||
initial_capacity, sizeof(*context->commands))) {
|
|
||||||
wr_context_destroy(context);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wr_context_destroy(wr_context* context)
|
|
||||||
{
|
|
||||||
if (!context)
|
|
||||||
return;
|
|
||||||
free(context->commands);
|
|
||||||
free(context->quads);
|
|
||||||
free(context->batches);
|
|
||||||
free(context->clip_stack);
|
|
||||||
free(context->state_stack);
|
|
||||||
free(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wr_context_clear(wr_context* context)
|
|
||||||
{
|
|
||||||
if (!context)
|
|
||||||
return;
|
|
||||||
context->command_count = 0;
|
|
||||||
context->quad_count = 0;
|
|
||||||
context->batch_count = 0;
|
|
||||||
context->clip_depth = 0;
|
|
||||||
context->state_depth = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wr_context_set_viewport(wr_context* context, wr_rect viewport)
|
|
||||||
{
|
|
||||||
if (context && wr_valid_rect(viewport))
|
|
||||||
context->viewport = viewport;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wr_context_set_transform(wr_context* context, wr_transform transform)
|
|
||||||
{
|
|
||||||
if (context && wr_valid_transform(transform))
|
|
||||||
context->transform = transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wr_context_set_opacity(wr_context* context, float opacity)
|
|
||||||
{
|
|
||||||
if (context && isfinite(opacity)) {
|
|
||||||
context->opacity = wr_clamp01(opacity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
wr_display_list_push_stacking_context(wr_context* context,
|
|
||||||
wr_transform transform,
|
|
||||||
float opacity)
|
|
||||||
{
|
|
||||||
wr_display_state state;
|
|
||||||
|
|
||||||
if (!context || !wr_valid_transform(transform) || !isfinite(opacity) ||
|
|
||||||
context->state_depth == SIZE_MAX)
|
|
||||||
return 0;
|
|
||||||
if (!wr_reserve((void**)&context->state_stack, &context->state_capacity,
|
|
||||||
context->state_depth + 1, sizeof(*context->state_stack)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
state.transform = context->transform;
|
|
||||||
state.opacity = context->opacity;
|
|
||||||
state.clip_depth = context->clip_depth;
|
|
||||||
context->state_stack[context->state_depth++] = state;
|
|
||||||
context->transform = wr_multiply_transform(context->transform, transform);
|
|
||||||
context->opacity = wr_clamp01(context->opacity * wr_clamp01(opacity));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wr_display_list_pop_stacking_context(wr_context* context)
|
|
||||||
{
|
|
||||||
wr_display_state state;
|
|
||||||
|
|
||||||
if (!context || !context->state_depth)
|
|
||||||
return;
|
|
||||||
state = context->state_stack[--context->state_depth];
|
|
||||||
context->transform = state.transform;
|
|
||||||
context->opacity = state.opacity;
|
|
||||||
context->clip_depth = state.clip_depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
wr_display_list_push_clip(wr_context* context, wr_rect clip)
|
|
||||||
{
|
|
||||||
wr_rect effective_clip;
|
|
||||||
|
|
||||||
if (!context || !wr_valid_rect(clip) ||
|
|
||||||
context->clip_depth == SIZE_MAX)
|
|
||||||
return 0;
|
|
||||||
if (!wr_reserve((void**)&context->clip_stack, &context->clip_capacity,
|
|
||||||
context->clip_depth + 1, sizeof(*context->clip_stack)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
effective_clip = clip;
|
|
||||||
if (context->clip_depth)
|
|
||||||
effective_clip = wr_intersect_rect(
|
|
||||||
context->clip_stack[context->clip_depth - 1], clip);
|
|
||||||
context->clip_stack[context->clip_depth++] = effective_clip;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
wr_display_list_pop_clip(wr_context* context)
|
|
||||||
{
|
|
||||||
if (context && context->clip_depth)
|
|
||||||
--context->clip_depth;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
wr_display_list_push_rect(wr_context* context, wr_rect rect, wr_color color)
|
|
||||||
{
|
|
||||||
return context ? wr_display_list_push_transformed_rect(
|
|
||||||
context, rect, color, context->transform) : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
wr_display_list_push_transformed_rect(wr_context* context, wr_rect rect,
|
|
||||||
wr_color color, wr_transform transform)
|
|
||||||
{
|
|
||||||
wr_rect clip_rect = context && context->clip_depth ?
|
|
||||||
context->clip_stack[context->clip_depth - 1] :
|
|
||||||
context ? context->viewport : wr_empty_rect();
|
|
||||||
uint8_t has_clip = context && context->clip_depth ? 1 : 0;
|
|
||||||
|
|
||||||
if (!context || !wr_valid_rect(rect) || !wr_valid_transform(transform))
|
|
||||||
return 0;
|
|
||||||
if (context->command_count == SIZE_MAX ||
|
|
||||||
context->command_count >= UINT32_MAX)
|
|
||||||
return 0;
|
|
||||||
if (!wr_reserve((void**)&context->commands, &context->command_capacity,
|
|
||||||
context->command_count + 1, sizeof(*context->commands)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
context->commands[context->command_count].rect = rect;
|
|
||||||
color = wr_normalize_color(color);
|
|
||||||
color.a *= context->opacity;
|
|
||||||
context->commands[context->command_count].color = color;
|
|
||||||
context->commands[context->command_count].transform = transform;
|
|
||||||
context->commands[context->command_count].clip_rect = clip_rect;
|
|
||||||
context->commands[context->command_count].has_clip = has_clip;
|
|
||||||
++context->command_count;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const wr_frame*
|
|
||||||
wr_context_build_frame(wr_context* context)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
if (!context)
|
|
||||||
return NULL;
|
|
||||||
context->quad_count = 0;
|
|
||||||
context->batch_count = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < context->command_count; ++i) {
|
|
||||||
wr_rect_command* command = &context->commands[i];
|
|
||||||
wr_gpu_quad* quad;
|
|
||||||
wr_gpu_batch* batch;
|
|
||||||
|
|
||||||
if (!wr_intersects(wr_transform_bounds(command->rect,
|
|
||||||
command->transform),
|
|
||||||
context->viewport) ||
|
|
||||||
(command->clip_rect.width <= 0.0f ||
|
|
||||||
command->clip_rect.height <= 0.0f))
|
|
||||||
continue;
|
|
||||||
if (context->quad_count == SIZE_MAX ||
|
|
||||||
context->quad_count >= UINT32_MAX ||
|
|
||||||
context->batch_count == SIZE_MAX ||
|
|
||||||
context->batch_count >= UINT32_MAX)
|
|
||||||
return NULL;
|
|
||||||
if (!wr_reserve((void**)&context->quads, &context->quad_capacity,
|
|
||||||
context->quad_count + 1, sizeof(*context->quads)) ||
|
|
||||||
!wr_reserve((void**)&context->batches, &context->batch_capacity,
|
|
||||||
context->batch_count + 1, sizeof(*context->batches)))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
quad = &context->quads[context->quad_count++];
|
|
||||||
quad->rect = command->rect;
|
|
||||||
quad->color = command->color;
|
|
||||||
|
|
||||||
if (context->batch_count &&
|
|
||||||
wr_colors_equal(context->batches[context->batch_count - 1].color,
|
|
||||||
command->color) &&
|
|
||||||
context->batches[context->batch_count - 1].transform.m11 ==
|
|
||||||
command->transform.m11 &&
|
|
||||||
context->batches[context->batch_count - 1].transform.m12 ==
|
|
||||||
command->transform.m12 &&
|
|
||||||
context->batches[context->batch_count - 1].transform.m21 ==
|
|
||||||
command->transform.m21 &&
|
|
||||||
context->batches[context->batch_count - 1].transform.m22 ==
|
|
||||||
command->transform.m22 &&
|
|
||||||
context->batches[context->batch_count - 1].transform.m31 ==
|
|
||||||
command->transform.m31 &&
|
|
||||||
context->batches[context->batch_count - 1].transform.m32 ==
|
|
||||||
command->transform.m32 &&
|
|
||||||
context->batches[context->batch_count - 1].has_clip ==
|
|
||||||
command->has_clip &&
|
|
||||||
(!command->has_clip ||
|
|
||||||
wr_rects_equal(context->batches[context->batch_count - 1].clip_rect,
|
|
||||||
command->clip_rect))) {
|
|
||||||
batch = &context->batches[context->batch_count - 1];
|
|
||||||
++batch->quad_count;
|
|
||||||
} else {
|
|
||||||
batch = &context->batches[context->batch_count++];
|
|
||||||
batch->first_quad = (uint32_t)(context->quad_count - 1);
|
|
||||||
batch->quad_count = 1;
|
|
||||||
batch->color = command->color;
|
|
||||||
batch->transform = command->transform;
|
|
||||||
batch->clip_rect = command->clip_rect;
|
|
||||||
batch->has_clip = command->has_clip;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context->frame.quads = context->quads;
|
|
||||||
context->frame.quad_count = context->quad_count;
|
|
||||||
context->frame.batches = context->batches;
|
|
||||||
context->frame.batch_count = context->batch_count;
|
|
||||||
return &context->frame;
|
|
||||||
}
|
|
||||||
|
|
@ -9,6 +9,13 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct wr_context wr_context;
|
typedef struct wr_context wr_context;
|
||||||
|
typedef uint64_t wr_item_id;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t key;
|
||||||
|
uint32_t width;
|
||||||
|
uint32_t height;
|
||||||
|
} wr_image_resource;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float x;
|
float x;
|
||||||
|
|
@ -34,9 +41,24 @@ typedef struct {
|
||||||
float m32;
|
float m32;
|
||||||
} wr_transform;
|
} wr_transform;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
wr_rect rect;
|
||||||
|
wr_rect tex_rect;
|
||||||
|
} wr_glyph;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WR_PRIMITIVE_SOLID = 0,
|
||||||
|
WR_PRIMITIVE_IMAGE = 1
|
||||||
|
} wr_primitive_kind;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
wr_rect rect;
|
wr_rect rect;
|
||||||
wr_color color;
|
wr_color color;
|
||||||
|
wr_rect tex_rect;
|
||||||
|
uint32_t image_key;
|
||||||
|
wr_item_id item_id;
|
||||||
|
uint8_t kind;
|
||||||
|
uint8_t active;
|
||||||
} wr_gpu_quad;
|
} wr_gpu_quad;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -46,6 +68,8 @@ typedef struct {
|
||||||
wr_transform transform;
|
wr_transform transform;
|
||||||
wr_rect clip_rect;
|
wr_rect clip_rect;
|
||||||
uint8_t has_clip;
|
uint8_t has_clip;
|
||||||
|
uint8_t kind;
|
||||||
|
uint32_t image_key;
|
||||||
} wr_gpu_batch;
|
} wr_gpu_batch;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
@ -55,6 +79,14 @@ typedef struct {
|
||||||
size_t batch_count;
|
size_t batch_count;
|
||||||
} wr_frame;
|
} wr_frame;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t quad_count;
|
||||||
|
uint32_t batch_count;
|
||||||
|
} wr_frame_packet_header;
|
||||||
|
|
||||||
|
#define WR_FRAME_PACKET_VERSION 1
|
||||||
|
|
||||||
/* Creates a retained display-list context. */
|
/* Creates a retained display-list context. */
|
||||||
wr_context* wr_context_create(size_t initial_capacity);
|
wr_context* wr_context_create(size_t initial_capacity);
|
||||||
void wr_context_destroy(wr_context* context);
|
void wr_context_destroy(wr_context* context);
|
||||||
|
|
@ -62,6 +94,21 @@ void wr_context_destroy(wr_context* context);
|
||||||
/* Removes every item from the retained display list. */
|
/* Removes every item from the retained display list. */
|
||||||
void wr_context_clear(wr_context* context);
|
void wr_context_clear(wr_context* context);
|
||||||
|
|
||||||
|
/* Clears transient image resources without releasing retained allocations. */
|
||||||
|
void wr_context_clear_images(wr_context* context);
|
||||||
|
|
||||||
|
/* Begins an atomic retained-scene update. Transactions may be nested. */
|
||||||
|
int wr_context_begin_transaction(wr_context* context);
|
||||||
|
|
||||||
|
/* Commits the innermost retained-scene update. */
|
||||||
|
int wr_context_commit_transaction(wr_context* context);
|
||||||
|
|
||||||
|
/* Rolls back the innermost retained-scene update. */
|
||||||
|
void wr_context_abort_transaction(wr_context* context);
|
||||||
|
|
||||||
|
/* Removes a retained display-list item by stable item ID. */
|
||||||
|
int wr_context_remove_item(wr_context* context, wr_item_id item_id);
|
||||||
|
|
||||||
/* Sets the viewport used for coarse CPU-side culling. */
|
/* Sets the viewport used for coarse CPU-side culling. */
|
||||||
void wr_context_set_viewport(wr_context* context, wr_rect viewport);
|
void wr_context_set_viewport(wr_context* context, wr_rect viewport);
|
||||||
|
|
||||||
|
|
@ -71,6 +118,13 @@ void wr_context_set_transform(wr_context* context, wr_transform transform);
|
||||||
/* Sets the opacity applied to subsequently recorded primitives. */
|
/* Sets the opacity applied to subsequently recorded primitives. */
|
||||||
void wr_context_set_opacity(wr_context* context, float opacity);
|
void wr_context_set_opacity(wr_context* context, float opacity);
|
||||||
|
|
||||||
|
/* Registers or updates an image resource referenced by display-list commands. */
|
||||||
|
int wr_context_register_image(wr_context* context, uint32_t image_key,
|
||||||
|
uint32_t width, uint32_t height);
|
||||||
|
|
||||||
|
/* Removes an image resource and invalidates frames referencing it. */
|
||||||
|
void wr_context_unregister_image(wr_context* context, uint32_t image_key);
|
||||||
|
|
||||||
/* Records a retained stacking-context boundary and restores it on pop. */
|
/* Records a retained stacking-context boundary and restores it on pop. */
|
||||||
int wr_display_list_push_stacking_context(wr_context* context,
|
int wr_display_list_push_stacking_context(wr_context* context,
|
||||||
wr_transform transform,
|
wr_transform transform,
|
||||||
|
|
@ -85,14 +139,57 @@ void wr_display_list_pop_clip(wr_context* context);
|
||||||
int wr_display_list_push_rect(wr_context* context, wr_rect rect,
|
int wr_display_list_push_rect(wr_context* context, wr_rect rect,
|
||||||
wr_color color);
|
wr_color color);
|
||||||
|
|
||||||
|
/* Adds a solid rectangle with a caller-supplied stable item ID. */
|
||||||
|
wr_item_id wr_display_list_push_rect_with_id(wr_context* context,
|
||||||
|
wr_item_id item_id,
|
||||||
|
wr_rect rect, wr_color color);
|
||||||
|
|
||||||
|
/* Updates an existing solid rectangle without rebuilding the scene. */
|
||||||
|
int wr_display_list_update_rect(wr_context* context, wr_item_id item_id,
|
||||||
|
wr_rect rect, wr_color color,
|
||||||
|
wr_transform transform);
|
||||||
|
|
||||||
|
/* Adds a GPU-tessellated linear gradient. */
|
||||||
|
int wr_display_list_push_linear_gradient(wr_context* context, wr_rect rect,
|
||||||
|
wr_color start, wr_color end,
|
||||||
|
int horizontal);
|
||||||
|
|
||||||
|
/* Adds a GPU-tessellated rounded rectangle. */
|
||||||
|
int wr_display_list_push_rounded_rect(wr_context* context, wr_rect rect,
|
||||||
|
wr_color color, float radius);
|
||||||
|
|
||||||
/* Explicit transform form for display-list builders. */
|
/* Explicit transform form for display-list builders. */
|
||||||
int wr_display_list_push_transformed_rect(wr_context* context, wr_rect rect,
|
int wr_display_list_push_transformed_rect(wr_context* context, wr_rect rect,
|
||||||
wr_color color,
|
wr_color color,
|
||||||
wr_transform transform);
|
wr_transform transform);
|
||||||
|
|
||||||
|
/* Adds an image primitive resolved by the compositor using image_key. */
|
||||||
|
int wr_display_list_push_image(wr_context* context, wr_rect rect,
|
||||||
|
uint32_t image_key, wr_rect tex_rect,
|
||||||
|
wr_color tint);
|
||||||
|
|
||||||
|
/* Adds an image with a caller-supplied stable item ID. */
|
||||||
|
wr_item_id wr_display_list_push_image_with_id(wr_context* context,
|
||||||
|
wr_item_id item_id,
|
||||||
|
wr_rect rect,
|
||||||
|
uint32_t image_key,
|
||||||
|
wr_rect tex_rect,
|
||||||
|
wr_color tint);
|
||||||
|
|
||||||
|
/* Records glyph quads sourced from a registered image atlas. */
|
||||||
|
int wr_display_list_push_glyph_run(wr_context* context, uint32_t image_key,
|
||||||
|
const wr_glyph* glyphs, size_t glyph_count,
|
||||||
|
wr_color color);
|
||||||
|
|
||||||
/* Builds the GPU-ready stream from the retained display list. */
|
/* Builds the GPU-ready stream from the retained display list. */
|
||||||
const wr_frame* wr_context_build_frame(wr_context* context);
|
const wr_frame* wr_context_build_frame(wr_context* context);
|
||||||
|
|
||||||
|
/* Returns the byte size required for a versioned, flat frame packet. */
|
||||||
|
size_t wr_frame_packet_size(const wr_frame* frame);
|
||||||
|
|
||||||
|
/* Serializes a frame into a flat buffer suitable for thread/IPC transfer. */
|
||||||
|
int wr_frame_serialize(const wr_frame* frame, void* buffer, size_t buffer_size);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
145
gfx/wr/wr_context.c
Normal file
145
gfx/wr/wr_context.c
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
#include <wr_internal.h>
|
||||||
|
|
||||||
|
wr_context*
|
||||||
|
wr_context_create(size_t initial_capacity)
|
||||||
|
{
|
||||||
|
wr_context* context = (wr_context*)calloc(1, sizeof(*context));
|
||||||
|
if (!context)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
context->viewport.x = -FLT_MAX;
|
||||||
|
context->viewport.y = -FLT_MAX;
|
||||||
|
context->viewport.width = FLT_MAX;
|
||||||
|
context->viewport.height = FLT_MAX;
|
||||||
|
context->transform = wr_identity_transform();
|
||||||
|
context->opacity = 1.0f;
|
||||||
|
context->next_item_id = 1;
|
||||||
|
|
||||||
|
if (initial_capacity &&
|
||||||
|
!wr_reserve((void**)&context->commands, &context->command_capacity,
|
||||||
|
initial_capacity, sizeof(*context->commands))) {
|
||||||
|
wr_context_destroy(context);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wr_context_destroy(wr_context* context)
|
||||||
|
{
|
||||||
|
if (!context)
|
||||||
|
return;
|
||||||
|
free(context->commands);
|
||||||
|
free(context->quads);
|
||||||
|
free(context->batches);
|
||||||
|
free(context->clip_stack);
|
||||||
|
free(context->state_stack);
|
||||||
|
free(context->images);
|
||||||
|
for (size_t i = 0; i < context->transaction_depth; ++i)
|
||||||
|
free(context->transactions[i].commands);
|
||||||
|
free(context->transactions);
|
||||||
|
free(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wr_context_clear(wr_context* context)
|
||||||
|
{
|
||||||
|
if (!context)
|
||||||
|
return;
|
||||||
|
context->command_count = 0;
|
||||||
|
context->quad_count = 0;
|
||||||
|
context->batch_count = 0;
|
||||||
|
context->clip_depth = 0;
|
||||||
|
context->state_depth = 0;
|
||||||
|
context->frame_valid = 0;
|
||||||
|
while (context->transaction_depth)
|
||||||
|
free(context->transactions[--context->transaction_depth].commands);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wr_context_set_viewport(wr_context* context, wr_rect viewport)
|
||||||
|
{
|
||||||
|
if (context && wr_valid_rect(viewport))
|
||||||
|
context->viewport = viewport;
|
||||||
|
if (context)
|
||||||
|
context->frame_valid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wr_context_set_transform(wr_context* context, wr_transform transform)
|
||||||
|
{
|
||||||
|
if (context && wr_valid_transform(transform))
|
||||||
|
context->transform = transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wr_context_set_opacity(wr_context* context, float opacity)
|
||||||
|
{
|
||||||
|
if (context && isfinite(opacity)) {
|
||||||
|
context->opacity = wr_clamp01(opacity);
|
||||||
|
context->frame_valid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_display_list_push_stacking_context(wr_context* context,
|
||||||
|
wr_transform transform,
|
||||||
|
float opacity)
|
||||||
|
{
|
||||||
|
wr_display_state state;
|
||||||
|
|
||||||
|
if (!context || !wr_valid_transform(transform) || !isfinite(opacity) ||
|
||||||
|
context->state_depth == SIZE_MAX)
|
||||||
|
return 0;
|
||||||
|
if (!wr_reserve((void**)&context->state_stack, &context->state_capacity,
|
||||||
|
context->state_depth + 1, sizeof(*context->state_stack)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
state.transform = context->transform;
|
||||||
|
state.opacity = context->opacity;
|
||||||
|
state.clip_depth = context->clip_depth;
|
||||||
|
context->state_stack[context->state_depth++] = state;
|
||||||
|
context->transform = wr_multiply_transform(context->transform, transform);
|
||||||
|
context->opacity = wr_clamp01(context->opacity * wr_clamp01(opacity));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wr_display_list_pop_stacking_context(wr_context* context)
|
||||||
|
{
|
||||||
|
wr_display_state state;
|
||||||
|
|
||||||
|
if (!context || !context->state_depth)
|
||||||
|
return;
|
||||||
|
state = context->state_stack[--context->state_depth];
|
||||||
|
context->transform = state.transform;
|
||||||
|
context->opacity = state.opacity;
|
||||||
|
context->clip_depth = state.clip_depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_display_list_push_clip(wr_context* context, wr_rect clip)
|
||||||
|
{
|
||||||
|
wr_rect effective_clip;
|
||||||
|
|
||||||
|
if (!context || !wr_valid_rect(clip) ||
|
||||||
|
context->clip_depth == SIZE_MAX)
|
||||||
|
return 0;
|
||||||
|
if (!wr_reserve((void**)&context->clip_stack, &context->clip_capacity,
|
||||||
|
context->clip_depth + 1, sizeof(*context->clip_stack)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
effective_clip = clip;
|
||||||
|
if (context->clip_depth)
|
||||||
|
effective_clip = wr_intersect_rect(
|
||||||
|
context->clip_stack[context->clip_depth - 1], clip);
|
||||||
|
context->clip_stack[context->clip_depth++] = effective_clip;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wr_display_list_pop_clip(wr_context* context)
|
||||||
|
{
|
||||||
|
if (context && context->clip_depth)
|
||||||
|
--context->clip_depth;
|
||||||
|
}
|
||||||
43
gfx/wr/wr_display_list.c
Normal file
43
gfx/wr/wr_display_list.c
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#include <wr_internal.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_display_list_push_rect(wr_context* context, wr_rect rect, wr_color color)
|
||||||
|
{
|
||||||
|
return context ? wr_display_list_push_transformed_rect(
|
||||||
|
context, rect, color, context->transform) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_display_list_push_transformed_rect(wr_context* context, wr_rect rect,
|
||||||
|
wr_color color, wr_transform transform)
|
||||||
|
{
|
||||||
|
wr_rect clip_rect = context && context->clip_depth ?
|
||||||
|
context->clip_stack[context->clip_depth - 1] :
|
||||||
|
context ? context->viewport : wr_empty_rect();
|
||||||
|
uint8_t has_clip = context && context->clip_depth ? 1 : 0;
|
||||||
|
|
||||||
|
if (!context || !wr_valid_rect(rect) || !wr_valid_transform(transform))
|
||||||
|
return 0;
|
||||||
|
if (context->command_count == SIZE_MAX ||
|
||||||
|
context->command_count >= UINT32_MAX)
|
||||||
|
return 0;
|
||||||
|
if (!wr_reserve((void**)&context->commands, &context->command_capacity,
|
||||||
|
context->command_count + 1, sizeof(*context->commands)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
context->commands[context->command_count].rect = rect;
|
||||||
|
color = wr_normalize_color(color);
|
||||||
|
color.a *= context->opacity;
|
||||||
|
context->commands[context->command_count].color = color;
|
||||||
|
context->commands[context->command_count].transform = transform;
|
||||||
|
context->commands[context->command_count].clip_rect = clip_rect;
|
||||||
|
context->commands[context->command_count].has_clip = has_clip;
|
||||||
|
context->commands[context->command_count].kind = WR_PRIMITIVE_SOLID;
|
||||||
|
context->commands[context->command_count].active = 1;
|
||||||
|
context->commands[context->command_count].image_key = 0;
|
||||||
|
context->commands[context->command_count].tex_rect = (wr_rect){ 0, 0, 1, 1 };
|
||||||
|
context->commands[context->command_count].item_id = context->next_item_id++;
|
||||||
|
++context->command_count;
|
||||||
|
context->frame_valid = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
105
gfx/wr/wr_frame.c
Normal file
105
gfx/wr/wr_frame.c
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
#include <wr_internal.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
wr_frame_has_image(const wr_context* context, uint32_t key)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < context->image_count; ++i)
|
||||||
|
if (context->images[i].key == key)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wr_frame*
|
||||||
|
wr_context_build_frame(wr_context* context)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
return NULL;
|
||||||
|
if (context->frame_valid)
|
||||||
|
return &context->frame;
|
||||||
|
context->quad_count = 0;
|
||||||
|
context->batch_count = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < context->command_count; ++i) {
|
||||||
|
wr_rect_command* command = &context->commands[i];
|
||||||
|
wr_gpu_quad* quad;
|
||||||
|
wr_gpu_batch* batch;
|
||||||
|
|
||||||
|
if (!command->active ||
|
||||||
|
(command->kind == WR_PRIMITIVE_IMAGE &&
|
||||||
|
!wr_frame_has_image(context, command->image_key)) ||
|
||||||
|
wr_command_occluded(context, i))
|
||||||
|
continue;
|
||||||
|
if (!wr_intersects(wr_transform_bounds(command->rect,
|
||||||
|
command->transform),
|
||||||
|
context->viewport) ||
|
||||||
|
(command->clip_rect.width <= 0.0f ||
|
||||||
|
command->clip_rect.height <= 0.0f))
|
||||||
|
continue;
|
||||||
|
if (context->quad_count == SIZE_MAX ||
|
||||||
|
context->quad_count >= UINT32_MAX ||
|
||||||
|
context->batch_count == SIZE_MAX ||
|
||||||
|
context->batch_count >= UINT32_MAX)
|
||||||
|
return NULL;
|
||||||
|
if (!wr_reserve((void**)&context->quads, &context->quad_capacity,
|
||||||
|
context->quad_count + 1, sizeof(*context->quads)) ||
|
||||||
|
!wr_reserve((void**)&context->batches, &context->batch_capacity,
|
||||||
|
context->batch_count + 1, sizeof(*context->batches)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
quad = &context->quads[context->quad_count++];
|
||||||
|
quad->rect = command->rect;
|
||||||
|
quad->color = command->color;
|
||||||
|
quad->tex_rect = command->tex_rect;
|
||||||
|
quad->image_key = command->image_key;
|
||||||
|
quad->item_id = command->item_id;
|
||||||
|
quad->active = command->active;
|
||||||
|
quad->kind = command->kind;
|
||||||
|
|
||||||
|
if (context->batch_count &&
|
||||||
|
context->batches[context->batch_count - 1].kind == command->kind &&
|
||||||
|
context->batches[context->batch_count - 1].image_key ==
|
||||||
|
command->image_key &&
|
||||||
|
wr_colors_equal(context->batches[context->batch_count - 1].color,
|
||||||
|
command->color) &&
|
||||||
|
context->batches[context->batch_count - 1].transform.m11 ==
|
||||||
|
command->transform.m11 &&
|
||||||
|
context->batches[context->batch_count - 1].transform.m12 ==
|
||||||
|
command->transform.m12 &&
|
||||||
|
context->batches[context->batch_count - 1].transform.m21 ==
|
||||||
|
command->transform.m21 &&
|
||||||
|
context->batches[context->batch_count - 1].transform.m22 ==
|
||||||
|
command->transform.m22 &&
|
||||||
|
context->batches[context->batch_count - 1].transform.m31 ==
|
||||||
|
command->transform.m31 &&
|
||||||
|
context->batches[context->batch_count - 1].transform.m32 ==
|
||||||
|
command->transform.m32 &&
|
||||||
|
context->batches[context->batch_count - 1].has_clip ==
|
||||||
|
command->has_clip &&
|
||||||
|
(!command->has_clip ||
|
||||||
|
wr_rects_equal(context->batches[context->batch_count - 1].clip_rect,
|
||||||
|
command->clip_rect))) {
|
||||||
|
batch = &context->batches[context->batch_count - 1];
|
||||||
|
++batch->quad_count;
|
||||||
|
} else {
|
||||||
|
batch = &context->batches[context->batch_count++];
|
||||||
|
batch->first_quad = (uint32_t)(context->quad_count - 1);
|
||||||
|
batch->quad_count = 1;
|
||||||
|
batch->color = command->color;
|
||||||
|
batch->transform = command->transform;
|
||||||
|
batch->clip_rect = command->clip_rect;
|
||||||
|
batch->has_clip = command->has_clip;
|
||||||
|
batch->kind = command->kind;
|
||||||
|
batch->image_key = command->image_key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context->frame.quads = context->quads;
|
||||||
|
context->frame.quad_count = context->quad_count;
|
||||||
|
context->frame.batches = context->batches;
|
||||||
|
context->frame.batch_count = context->batch_count;
|
||||||
|
context->frame_valid = 1;
|
||||||
|
return &context->frame;
|
||||||
|
}
|
||||||
59
gfx/wr/wr_frame_packet.c
Normal file
59
gfx/wr/wr_frame_packet.c
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
#include "webrender.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
wr_packet_size_mul_overflow(size_t a, size_t b)
|
||||||
|
{
|
||||||
|
return b != 0 && a > SIZE_MAX / b;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
wr_frame_packet_size(const wr_frame* frame)
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (!frame || frame->quad_count > UINT32_MAX ||
|
||||||
|
frame->batch_count > UINT32_MAX ||
|
||||||
|
(frame->quad_count && !frame->quads) ||
|
||||||
|
(frame->batch_count && !frame->batches))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size = sizeof(wr_frame_packet_header);
|
||||||
|
if (wr_packet_size_mul_overflow(frame->quad_count, sizeof(*frame->quads)) ||
|
||||||
|
wr_packet_size_mul_overflow(frame->batch_count, sizeof(*frame->batches)))
|
||||||
|
return 0;
|
||||||
|
if (size > SIZE_MAX - frame->quad_count * sizeof(*frame->quads))
|
||||||
|
return 0;
|
||||||
|
size += frame->quad_count * sizeof(*frame->quads);
|
||||||
|
if (size > SIZE_MAX - frame->batch_count * sizeof(*frame->batches))
|
||||||
|
return 0;
|
||||||
|
return size + frame->batch_count * sizeof(*frame->batches);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_frame_serialize(const wr_frame* frame, void* buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
wr_frame_packet_header header;
|
||||||
|
size_t required = wr_frame_packet_size(frame);
|
||||||
|
unsigned char* output = (unsigned char*)buffer;
|
||||||
|
|
||||||
|
if (!required || !buffer || buffer_size < required)
|
||||||
|
return 0;
|
||||||
|
header.version = WR_FRAME_PACKET_VERSION;
|
||||||
|
header.quad_count = (uint32_t)frame->quad_count;
|
||||||
|
header.batch_count = (uint32_t)frame->batch_count;
|
||||||
|
memcpy(output, &header, sizeof(header));
|
||||||
|
output += sizeof(header);
|
||||||
|
if (frame->quad_count) {
|
||||||
|
memcpy(output, frame->quads,
|
||||||
|
frame->quad_count * sizeof(*frame->quads));
|
||||||
|
output += frame->quad_count * sizeof(*frame->quads);
|
||||||
|
}
|
||||||
|
if (frame->batch_count) {
|
||||||
|
memcpy(output, frame->batches,
|
||||||
|
frame->batch_count * sizeof(*frame->batches));
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
82
gfx/wr/wr_internal.h
Normal file
82
gfx/wr/wr_internal.h
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
#ifndef GFX_WR_INTERNAL_H
|
||||||
|
#define GFX_WR_INTERNAL_H
|
||||||
|
|
||||||
|
#include <webrender.h>
|
||||||
|
#include <float.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
wr_rect rect;
|
||||||
|
wr_color color;
|
||||||
|
wr_transform transform;
|
||||||
|
wr_rect clip_rect;
|
||||||
|
uint8_t has_clip;
|
||||||
|
uint8_t kind;
|
||||||
|
uint8_t active;
|
||||||
|
uint32_t image_key;
|
||||||
|
wr_rect tex_rect;
|
||||||
|
wr_item_id item_id;
|
||||||
|
} wr_rect_command;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
wr_transform transform;
|
||||||
|
float opacity;
|
||||||
|
size_t clip_depth;
|
||||||
|
} wr_display_state;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
size_t command_count;
|
||||||
|
wr_rect_command* commands;
|
||||||
|
} wr_scene_transaction;
|
||||||
|
|
||||||
|
struct wr_context {
|
||||||
|
wr_rect_command* commands;
|
||||||
|
size_t command_count;
|
||||||
|
size_t command_capacity;
|
||||||
|
|
||||||
|
wr_gpu_quad* quads;
|
||||||
|
size_t quad_count;
|
||||||
|
size_t quad_capacity;
|
||||||
|
|
||||||
|
wr_gpu_batch* batches;
|
||||||
|
size_t batch_count;
|
||||||
|
size_t batch_capacity;
|
||||||
|
|
||||||
|
wr_rect viewport;
|
||||||
|
wr_transform transform;
|
||||||
|
float opacity;
|
||||||
|
wr_rect* clip_stack;
|
||||||
|
size_t clip_depth;
|
||||||
|
size_t clip_capacity;
|
||||||
|
wr_display_state* state_stack;
|
||||||
|
size_t state_depth;
|
||||||
|
size_t state_capacity;
|
||||||
|
wr_item_id next_item_id;
|
||||||
|
wr_image_resource* images;
|
||||||
|
size_t image_count;
|
||||||
|
size_t image_capacity;
|
||||||
|
wr_scene_transaction* transactions;
|
||||||
|
size_t transaction_depth;
|
||||||
|
size_t transaction_capacity;
|
||||||
|
int frame_valid;
|
||||||
|
wr_frame frame;
|
||||||
|
};
|
||||||
|
|
||||||
|
int wr_size_mul_overflow(size_t, size_t);
|
||||||
|
int wr_reserve(void**, size_t*, size_t, size_t);
|
||||||
|
int wr_valid_rect(wr_rect);
|
||||||
|
int wr_valid_transform(wr_transform);
|
||||||
|
wr_transform wr_identity_transform(void);
|
||||||
|
wr_transform wr_multiply_transform(wr_transform, wr_transform);
|
||||||
|
wr_rect wr_empty_rect(void);
|
||||||
|
float wr_clamp01(float);
|
||||||
|
wr_color wr_normalize_color(wr_color);
|
||||||
|
int wr_colors_equal(wr_color, wr_color);
|
||||||
|
int wr_rects_equal(wr_rect, wr_rect);
|
||||||
|
int wr_intersects(wr_rect, wr_rect);
|
||||||
|
wr_rect wr_intersect_rect(wr_rect, wr_rect);
|
||||||
|
wr_rect wr_transform_bounds(wr_rect, wr_transform);
|
||||||
|
int wr_command_occluded(const wr_context*, size_t);
|
||||||
|
#endif
|
||||||
251
gfx/wr/wr_retained.c
Normal file
251
gfx/wr/wr_retained.c
Normal file
|
|
@ -0,0 +1,251 @@
|
||||||
|
#include <wr_internal.h>
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
wr_image_index(const wr_context* context, uint32_t key)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; context && i < context->image_count; ++i)
|
||||||
|
if (context->images[i].key == key)
|
||||||
|
return i;
|
||||||
|
return SIZE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
wr_item_index(const wr_context* context, wr_item_id item)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; context && i < context->command_count; ++i)
|
||||||
|
if (context->commands[i].active && context->commands[i].item_id == item)
|
||||||
|
return i;
|
||||||
|
return SIZE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
wr_rect_contains(wr_rect outer, wr_rect inner)
|
||||||
|
{
|
||||||
|
return inner.x >= outer.x && inner.y >= outer.y &&
|
||||||
|
inner.x + inner.width <= outer.x + outer.width &&
|
||||||
|
inner.y + inner.height <= outer.y + outer.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
wr_append(wr_context* context, wr_item_id item, wr_rect rect, wr_color color,
|
||||||
|
uint8_t kind, uint32_t image_key, wr_rect tex_rect)
|
||||||
|
{
|
||||||
|
wr_rect clip = context->clip_depth
|
||||||
|
? context->clip_stack[context->clip_depth - 1] : context->viewport;
|
||||||
|
if (!context || !wr_valid_rect(rect) ||
|
||||||
|
(kind == WR_PRIMITIVE_IMAGE &&
|
||||||
|
(wr_image_index(context, image_key) == SIZE_MAX ||
|
||||||
|
tex_rect.width == 0.0f || tex_rect.height == 0.0f)))
|
||||||
|
return 0;
|
||||||
|
if (!wr_reserve((void**)&context->commands, &context->command_capacity,
|
||||||
|
context->command_count + 1, sizeof(*context->commands)))
|
||||||
|
return 0;
|
||||||
|
if (!item) {
|
||||||
|
item = context->next_item_id++;
|
||||||
|
if (!item)
|
||||||
|
item = context->next_item_id++;
|
||||||
|
}
|
||||||
|
if (wr_item_index(context, item) != SIZE_MAX)
|
||||||
|
return 0;
|
||||||
|
context->commands[context->command_count] = (wr_rect_command){
|
||||||
|
rect, wr_normalize_color(color), context->transform, clip,
|
||||||
|
context->clip_depth ? 1 : 0, kind, 1, image_key, tex_rect, item };
|
||||||
|
context->commands[context->command_count].color.a *= context->opacity;
|
||||||
|
++context->command_count;
|
||||||
|
context->frame_valid = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_context_register_image(wr_context* context, uint32_t key,
|
||||||
|
uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
size_t index;
|
||||||
|
if (!context || !key || !width || !height)
|
||||||
|
return 0;
|
||||||
|
index = wr_image_index(context, key);
|
||||||
|
if (index != SIZE_MAX) {
|
||||||
|
context->images[index].width = width;
|
||||||
|
context->images[index].height = height;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!wr_reserve((void**)&context->images, &context->image_capacity,
|
||||||
|
context->image_count + 1, sizeof(*context->images)))
|
||||||
|
return 0;
|
||||||
|
context->images[context->image_count++] = (wr_image_resource){ key, width, height };
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wr_context_unregister_image(wr_context* context, uint32_t key)
|
||||||
|
{
|
||||||
|
size_t index = wr_image_index(context, key);
|
||||||
|
if (index == SIZE_MAX)
|
||||||
|
return;
|
||||||
|
context->images[index] = context->images[--context->image_count];
|
||||||
|
context->frame_valid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wr_context_clear_images(wr_context* context)
|
||||||
|
{
|
||||||
|
if (context) {
|
||||||
|
context->image_count = 0;
|
||||||
|
context->frame_valid = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_context_begin_transaction(wr_context* context)
|
||||||
|
{
|
||||||
|
wr_scene_transaction transaction = { 0, NULL };
|
||||||
|
if (!context || !wr_reserve((void**)&context->transactions,
|
||||||
|
&context->transaction_capacity, context->transaction_depth + 1,
|
||||||
|
sizeof(*context->transactions)))
|
||||||
|
return 0;
|
||||||
|
transaction.command_count = context->command_count;
|
||||||
|
if (transaction.command_count) {
|
||||||
|
transaction.commands = malloc(transaction.command_count * sizeof(*transaction.commands));
|
||||||
|
if (!transaction.commands)
|
||||||
|
return 0;
|
||||||
|
memcpy(transaction.commands, context->commands,
|
||||||
|
transaction.command_count * sizeof(*transaction.commands));
|
||||||
|
}
|
||||||
|
context->transactions[context->transaction_depth++] = transaction;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_context_commit_transaction(wr_context* context)
|
||||||
|
{
|
||||||
|
if (!context || !context->transaction_depth)
|
||||||
|
return 0;
|
||||||
|
free(context->transactions[--context->transaction_depth].commands);
|
||||||
|
context->frame_valid = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
wr_context_abort_transaction(wr_context* context)
|
||||||
|
{
|
||||||
|
wr_scene_transaction transaction;
|
||||||
|
if (!context || !context->transaction_depth)
|
||||||
|
return;
|
||||||
|
transaction = context->transactions[--context->transaction_depth];
|
||||||
|
if (transaction.command_count)
|
||||||
|
memcpy(context->commands, transaction.commands,
|
||||||
|
transaction.command_count * sizeof(*context->commands));
|
||||||
|
context->command_count = transaction.command_count;
|
||||||
|
free(transaction.commands);
|
||||||
|
context->frame_valid = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_context_remove_item(wr_context* context, wr_item_id item)
|
||||||
|
{
|
||||||
|
size_t index = wr_item_index(context, item);
|
||||||
|
if (index == SIZE_MAX)
|
||||||
|
return 0;
|
||||||
|
context->commands[index].active = 0;
|
||||||
|
context->frame_valid = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wr_item_id
|
||||||
|
wr_display_list_push_rect_with_id(wr_context* context, wr_item_id item,
|
||||||
|
wr_rect rect, wr_color color)
|
||||||
|
{
|
||||||
|
return wr_append(context, item, rect, color, WR_PRIMITIVE_SOLID, 0,
|
||||||
|
(wr_rect){ 0, 0, 1, 1 }) ? item : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_display_list_update_rect(wr_context* context, wr_item_id item, wr_rect rect,
|
||||||
|
wr_color color, wr_transform transform)
|
||||||
|
{
|
||||||
|
size_t index = wr_item_index(context, item);
|
||||||
|
if (index == SIZE_MAX || !wr_valid_rect(rect) || !wr_valid_transform(transform))
|
||||||
|
return 0;
|
||||||
|
context->commands[index].rect = rect;
|
||||||
|
context->commands[index].color = wr_normalize_color(color);
|
||||||
|
context->commands[index].color.a *= context->opacity;
|
||||||
|
context->commands[index].transform = transform;
|
||||||
|
context->frame_valid = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_display_list_push_image(wr_context* context, wr_rect rect, uint32_t key,
|
||||||
|
wr_rect tex_rect, wr_color tint)
|
||||||
|
{ return wr_append(context, 0, rect, tint, WR_PRIMITIVE_IMAGE, key, tex_rect); }
|
||||||
|
|
||||||
|
wr_item_id
|
||||||
|
wr_display_list_push_image_with_id(wr_context* context, wr_item_id item,
|
||||||
|
wr_rect rect, uint32_t key, wr_rect tex,
|
||||||
|
wr_color tint)
|
||||||
|
{ return wr_append(context, item, rect, tint, WR_PRIMITIVE_IMAGE, key, tex) ? item : 0; }
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_display_list_push_linear_gradient(wr_context* context, wr_rect rect,
|
||||||
|
wr_color start, wr_color end, int horizontal)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
for (i = 0; i < 32; ++i) {
|
||||||
|
float a = (float)i / 32.0f, b = (float)(i + 1) / 32.0f;
|
||||||
|
wr_rect slice = rect;
|
||||||
|
wr_color color = { start.r + (end.r-start.r)*(a+b)*.5f,
|
||||||
|
start.g + (end.g-start.g)*(a+b)*.5f, start.b + (end.b-start.b)*(a+b)*.5f,
|
||||||
|
start.a + (end.a-start.a)*(a+b)*.5f };
|
||||||
|
if (horizontal) { slice.x += rect.width*a; slice.width = rect.width*(b-a); }
|
||||||
|
else { slice.y += rect.height*a; slice.height = rect.height*(b-a); }
|
||||||
|
if (!wr_append(context, 0, slice, color, WR_PRIMITIVE_SOLID, 0,
|
||||||
|
(wr_rect){ 0, 0, 1, 1 })) return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_display_list_push_rounded_rect(wr_context* context, wr_rect rect,
|
||||||
|
wr_color color, float radius)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
(void)radius;
|
||||||
|
for (i = 0; i < 16; ++i) {
|
||||||
|
wr_rect slice = { rect.x, rect.y + rect.height * i / 16.0f,
|
||||||
|
rect.width, rect.height / 16.0f };
|
||||||
|
if (!wr_append(context, 0, slice, color, WR_PRIMITIVE_SOLID, 0,
|
||||||
|
(wr_rect){ 0, 0, 1, 1 }))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_display_list_push_glyph_run(wr_context* context, uint32_t key,
|
||||||
|
const wr_glyph* glyphs, size_t count, wr_color color)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; glyphs && i < count; ++i)
|
||||||
|
if (!wr_append(context, 0, glyphs[i].rect, color, WR_PRIMITIVE_IMAGE,
|
||||||
|
key, glyphs[i].tex_rect)) return 0;
|
||||||
|
return glyphs && count != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_command_occluded(const wr_context* context, size_t index)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
wr_rect bounds = wr_transform_bounds(context->commands[index].rect,
|
||||||
|
context->commands[index].transform);
|
||||||
|
for (i = index + 1; i < context->command_count; ++i) {
|
||||||
|
const wr_rect_command* covering = &context->commands[i];
|
||||||
|
wr_rect cover;
|
||||||
|
if (!covering->active || covering->kind != WR_PRIMITIVE_SOLID ||
|
||||||
|
covering->color.a != 1.0f) continue;
|
||||||
|
cover = wr_transform_bounds(covering->rect, covering->transform);
|
||||||
|
if (wr_rect_contains(cover, bounds)) return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
160
gfx/wr/wr_util.c
Normal file
160
gfx/wr/wr_util.c
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
#include <wr_internal.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_size_mul_overflow(size_t a, size_t b)
|
||||||
|
{
|
||||||
|
return b != 0 && a > SIZE_MAX / b;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_reserve(void** data, size_t* capacity, size_t count, size_t element_size)
|
||||||
|
{
|
||||||
|
size_t new_capacity;
|
||||||
|
void* new_data;
|
||||||
|
|
||||||
|
if (count <= *capacity)
|
||||||
|
return 1;
|
||||||
|
if (element_size == 0 || wr_size_mul_overflow(count, element_size))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
new_capacity = *capacity ? *capacity : 8;
|
||||||
|
while (new_capacity < count) {
|
||||||
|
if (new_capacity > SIZE_MAX / 2) {
|
||||||
|
new_capacity = count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
new_capacity *= 2;
|
||||||
|
}
|
||||||
|
if (wr_size_mul_overflow(new_capacity, element_size))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
new_data = realloc(*data, new_capacity * element_size);
|
||||||
|
if (!new_data)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*data = new_data;
|
||||||
|
*capacity = new_capacity;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_valid_rect(wr_rect rect)
|
||||||
|
{
|
||||||
|
return isfinite(rect.x) && isfinite(rect.y) &&
|
||||||
|
isfinite(rect.width) && isfinite(rect.height) &&
|
||||||
|
rect.width > 0.0f && rect.height > 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_valid_transform(wr_transform transform)
|
||||||
|
{
|
||||||
|
return isfinite(transform.m11) && isfinite(transform.m12) &&
|
||||||
|
isfinite(transform.m21) && isfinite(transform.m22) &&
|
||||||
|
isfinite(transform.m31) && isfinite(transform.m32);
|
||||||
|
}
|
||||||
|
|
||||||
|
wr_transform
|
||||||
|
wr_identity_transform(void)
|
||||||
|
{
|
||||||
|
wr_transform transform = { 1, 0, 0, 1, 0, 0 };
|
||||||
|
return transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
wr_transform
|
||||||
|
wr_multiply_transform(wr_transform a, wr_transform b)
|
||||||
|
{
|
||||||
|
wr_transform result;
|
||||||
|
result.m11 = a.m11 * b.m11 + a.m21 * b.m12;
|
||||||
|
result.m12 = a.m12 * b.m11 + a.m22 * b.m12;
|
||||||
|
result.m21 = a.m11 * b.m21 + a.m21 * b.m22;
|
||||||
|
result.m22 = a.m12 * b.m21 + a.m22 * b.m22;
|
||||||
|
result.m31 = a.m11 * b.m31 + a.m21 * b.m32 + a.m31;
|
||||||
|
result.m32 = a.m12 * b.m31 + a.m22 * b.m32 + a.m32;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
wr_rect
|
||||||
|
wr_empty_rect(void)
|
||||||
|
{
|
||||||
|
wr_rect rect = { 0, 0, 0, 0 };
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
wr_clamp01(float value)
|
||||||
|
{
|
||||||
|
if (value < 0.0f)
|
||||||
|
return 0.0f;
|
||||||
|
if (value > 1.0f)
|
||||||
|
return 1.0f;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
wr_color
|
||||||
|
wr_normalize_color(wr_color color)
|
||||||
|
{
|
||||||
|
color.r = wr_clamp01(color.r);
|
||||||
|
color.g = wr_clamp01(color.g);
|
||||||
|
color.b = wr_clamp01(color.b);
|
||||||
|
color.a = wr_clamp01(color.a);
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_colors_equal(wr_color a, wr_color b)
|
||||||
|
{
|
||||||
|
return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_rects_equal(wr_rect a, wr_rect b)
|
||||||
|
{
|
||||||
|
return a.x == b.x && a.y == b.y &&
|
||||||
|
a.width == b.width && a.height == b.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
wr_intersects(wr_rect a, wr_rect b)
|
||||||
|
{
|
||||||
|
return a.x < b.x + b.width && a.x + a.width > b.x &&
|
||||||
|
a.y < b.y + b.height && a.y + a.height > b.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
wr_rect
|
||||||
|
wr_intersect_rect(wr_rect a, wr_rect b)
|
||||||
|
{
|
||||||
|
float left = a.x > b.x ? a.x : b.x;
|
||||||
|
float top = a.y > b.y ? a.y : b.y;
|
||||||
|
float right = a.x + a.width < b.x + b.width ?
|
||||||
|
a.x + a.width : b.x + b.width;
|
||||||
|
float bottom = a.y + a.height < b.y + b.height ?
|
||||||
|
a.y + a.height : b.y + b.height;
|
||||||
|
wr_rect result = { left, top, right - left, bottom - top };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
wr_rect
|
||||||
|
wr_transform_bounds(wr_rect rect, wr_transform transform)
|
||||||
|
{
|
||||||
|
float x1 = rect.x * transform.m11 + rect.y * transform.m21 + transform.m31;
|
||||||
|
float y1 = rect.x * transform.m12 + rect.y * transform.m22 + transform.m32;
|
||||||
|
float x2 = (rect.x + rect.width) * transform.m11 +
|
||||||
|
rect.y * transform.m21 + transform.m31;
|
||||||
|
float y2 = (rect.x + rect.width) * transform.m12 +
|
||||||
|
rect.y * transform.m22 + transform.m32;
|
||||||
|
float x3 = rect.x * transform.m11 +
|
||||||
|
(rect.y + rect.height) * transform.m21 + transform.m31;
|
||||||
|
float y3 = rect.x * transform.m12 +
|
||||||
|
(rect.y + rect.height) * transform.m22 + transform.m32;
|
||||||
|
float x4 = (rect.x + rect.width) * transform.m11 +
|
||||||
|
(rect.y + rect.height) * transform.m21 + transform.m31;
|
||||||
|
float y4 = (rect.x + rect.width) * transform.m12 +
|
||||||
|
(rect.y + rect.height) * transform.m22 + transform.m32;
|
||||||
|
float left = fminf(fminf(x1, x2), fminf(x3, x4));
|
||||||
|
float right = fmaxf(fmaxf(x1, x2), fmaxf(x3, x4));
|
||||||
|
float top = fminf(fminf(y1, y2), fminf(y3, y4));
|
||||||
|
float bottom = fmaxf(fmaxf(y1, y2), fmaxf(y3, y4));
|
||||||
|
wr_rect result = { left, top, right - left, bottom - top };
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -304,6 +304,17 @@ var snapshotFormatters = {
|
||||||
: "BasicLayers (" + strings.GetStringFromName("mainThreadNoOMTC") + ")";
|
: "BasicLayers (" + strings.GetStringFromName("mainThreadNoOMTC") + ")";
|
||||||
addRow("features", "compositing", compositor);
|
addRow("features", "compositing", compositor);
|
||||||
|
|
||||||
|
let webRenderEnabled = false;
|
||||||
|
try {
|
||||||
|
webRenderEnabled = Services.prefs.getBoolPref("gfx.webrender.enabled");
|
||||||
|
} catch (e) {
|
||||||
|
// Keep about:support usable if the preference is unavailable in a build.
|
||||||
|
}
|
||||||
|
addRow("features", "webRender",
|
||||||
|
strings.GetStringFromName(webRenderEnabled
|
||||||
|
? "webRenderEnabled"
|
||||||
|
: "webRenderDisabled"));
|
||||||
|
|
||||||
let acceleratedWindows = data.numAcceleratedWindows + "/" + data.numTotalWindows;
|
let acceleratedWindows = data.numAcceleratedWindows + "/" + data.numTotalWindows;
|
||||||
if (data.windowLayerManagerType) {
|
if (data.windowLayerManagerType) {
|
||||||
acceleratedWindows += " " + data.windowLayerManagerType;
|
acceleratedWindows += " " + data.windowLayerManagerType;
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,9 @@ blockedMismatchedVersion = Blocked for your graphics driver version mismatch bet
|
||||||
clearTypeParameters = ClearType Parameters
|
clearTypeParameters = ClearType Parameters
|
||||||
|
|
||||||
compositing = Compositing
|
compositing = Compositing
|
||||||
|
webRender = WebRender
|
||||||
|
webRenderEnabled = Enabled
|
||||||
|
webRenderDisabled = Disabled
|
||||||
hardwareH264 = Hardware H264 Decoding
|
hardwareH264 = Hardware H264 Decoding
|
||||||
hardwareVP9 = Hardware VP9 Decoding
|
hardwareVP9 = Hardware VP9 Decoding
|
||||||
audioBackend = Audio Backend
|
audioBackend = Audio Backend
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue