mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1088417 - DecomposeIntoNoRepeatRects for D3D11. - r=nical
This commit is contained in:
parent
afdef4dd16
commit
3ca0b077db
@ -193,5 +193,170 @@ Compositor::DrawDiagnosticsInternal(DiagnosticFlags aFlags,
|
||||
aTransform);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
static float
|
||||
WrapTexCoord(float v)
|
||||
{
|
||||
// fmodf gives negative results for negative numbers;
|
||||
// that is, fmodf(0.75, 1.0) == 0.75, but
|
||||
// fmodf(-0.75, 1.0) == -0.75. For the negative case,
|
||||
// the result we need is 0.25, so we add 1.0f.
|
||||
if (v < 0.0f) {
|
||||
return 1.0f + fmodf(v, 1.0f);
|
||||
}
|
||||
|
||||
return fmodf(v, 1.0f);
|
||||
}
|
||||
|
||||
static void
|
||||
SetRects(size_t n,
|
||||
decomposedRectArrayT* aLayerRects,
|
||||
decomposedRectArrayT* aTextureRects,
|
||||
float x0, float y0, float x1, float y1,
|
||||
float tx0, float ty0, float tx1, float ty1,
|
||||
bool flip_y)
|
||||
{
|
||||
if (flip_y) {
|
||||
std::swap(ty0, ty1);
|
||||
}
|
||||
(*aLayerRects)[n] = gfx::Rect(x0, y0, x1 - x0, y1 - y0);
|
||||
(*aTextureRects)[n] = gfx::Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static inline bool
|
||||
FuzzyEqual(float a, float b)
|
||||
{
|
||||
return fabs(a - b) < 0.0001f;
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t
|
||||
DecomposeIntoNoRepeatRects(const gfx::Rect& aRect,
|
||||
const gfx::Rect& aTexCoordRect,
|
||||
decomposedRectArrayT* aLayerRects,
|
||||
decomposedRectArrayT* aTextureRects)
|
||||
{
|
||||
gfx::Rect texCoordRect = aTexCoordRect;
|
||||
|
||||
// If the texture should be flipped, it will have negative height. Detect that
|
||||
// here and compensate for it. We will flip each rect as we emit it.
|
||||
bool flipped = false;
|
||||
if (texCoordRect.height < 0) {
|
||||
flipped = true;
|
||||
texCoordRect.y += texCoordRect.height;
|
||||
texCoordRect.height = -texCoordRect.height;
|
||||
}
|
||||
|
||||
// Wrap the texture coordinates so they are within [0,1] and cap width/height
|
||||
// at 1. We rely on this below.
|
||||
texCoordRect = gfx::Rect(gfx::Point(WrapTexCoord(texCoordRect.x),
|
||||
WrapTexCoord(texCoordRect.y)),
|
||||
gfx::Size(std::min(texCoordRect.width, 1.0f),
|
||||
std::min(texCoordRect.height, 1.0f)));
|
||||
|
||||
NS_ASSERTION(texCoordRect.x >= 0.0f && texCoordRect.x <= 1.0f &&
|
||||
texCoordRect.y >= 0.0f && texCoordRect.y <= 1.0f &&
|
||||
texCoordRect.width >= 0.0f && texCoordRect.width <= 1.0f &&
|
||||
texCoordRect.height >= 0.0f && texCoordRect.height <= 1.0f &&
|
||||
texCoordRect.XMost() >= 0.0f && texCoordRect.XMost() <= 2.0f &&
|
||||
texCoordRect.YMost() >= 0.0f && texCoordRect.YMost() <= 2.0f,
|
||||
"We just wrapped the texture coordinates, didn't we?");
|
||||
|
||||
// Get the top left and bottom right points of the rectangle. Note that
|
||||
// tl.x/tl.y are within [0,1] but br.x/br.y are within [0,2].
|
||||
gfx::Point tl = texCoordRect.TopLeft();
|
||||
gfx::Point br = texCoordRect.BottomRight();
|
||||
|
||||
NS_ASSERTION(tl.x >= 0.0f && tl.x <= 1.0f &&
|
||||
tl.y >= 0.0f && tl.y <= 1.0f &&
|
||||
br.x >= tl.x && br.x <= 2.0f &&
|
||||
br.y >= tl.y && br.y <= 2.0f &&
|
||||
br.x - tl.x <= 1.0f &&
|
||||
br.y - tl.y <= 1.0f,
|
||||
"Somehow generated invalid texture coordinates");
|
||||
|
||||
// Then check if we wrap in either the x or y axis.
|
||||
bool xwrap = br.x > 1.0f;
|
||||
bool ywrap = br.y > 1.0f;
|
||||
|
||||
// If xwrap is false, the texture will be sampled from tl.x .. br.x.
|
||||
// If xwrap is true, then it will be split into tl.x .. 1.0, and
|
||||
// 0.0 .. WrapTexCoord(br.x). Same for the Y axis. The destination
|
||||
// rectangle is also split appropriately, according to the calculated
|
||||
// xmid/ymid values.
|
||||
if (!xwrap && !ywrap) {
|
||||
SetRects(0, aLayerRects, aTextureRects,
|
||||
aRect.x, aRect.y, aRect.XMost(), aRect.YMost(),
|
||||
tl.x, tl.y, br.x, br.y,
|
||||
flipped);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If we are dealing with wrapping br.x and br.y are greater than 1.0 so
|
||||
// wrap them here as well.
|
||||
br = gfx::Point(xwrap ? WrapTexCoord(br.x) : br.x,
|
||||
ywrap ? WrapTexCoord(br.y) : br.y);
|
||||
|
||||
// If we wrap around along the x axis, we will draw first from
|
||||
// tl.x .. 1.0 and then from 0.0 .. br.x (which we just wrapped above).
|
||||
// The same applies for the Y axis. The midpoints we calculate here are
|
||||
// only valid if we actually wrap around.
|
||||
GLfloat xmid = aRect.x + (1.0f - tl.x) / texCoordRect.width * aRect.width;
|
||||
GLfloat ymid = aRect.y + (1.0f - tl.y) / texCoordRect.height * aRect.height;
|
||||
|
||||
NS_ASSERTION(!xwrap ||
|
||||
(xmid > aRect.x &&
|
||||
xmid < aRect.XMost() &&
|
||||
FuzzyEqual((xmid - aRect.x) + (aRect.XMost() - xmid), aRect.width)),
|
||||
"xmid should be within [x,XMost()] and the wrapped rect should have the same width");
|
||||
NS_ASSERTION(!ywrap ||
|
||||
(ymid > aRect.y &&
|
||||
ymid < aRect.YMost() &&
|
||||
FuzzyEqual((ymid - aRect.y) + (aRect.YMost() - ymid), aRect.height)),
|
||||
"ymid should be within [y,YMost()] and the wrapped rect should have the same height");
|
||||
|
||||
if (!xwrap && ywrap) {
|
||||
SetRects(0, aLayerRects, aTextureRects,
|
||||
aRect.x, aRect.y, aRect.XMost(), ymid,
|
||||
tl.x, tl.y, br.x, 1.0f,
|
||||
flipped);
|
||||
SetRects(1, aLayerRects, aTextureRects,
|
||||
aRect.x, ymid, aRect.XMost(), aRect.YMost(),
|
||||
tl.x, 0.0f, br.x, br.y,
|
||||
flipped);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (xwrap && !ywrap) {
|
||||
SetRects(0, aLayerRects, aTextureRects,
|
||||
aRect.x, aRect.y, xmid, aRect.YMost(),
|
||||
tl.x, tl.y, 1.0f, br.y,
|
||||
flipped);
|
||||
SetRects(1, aLayerRects, aTextureRects,
|
||||
xmid, aRect.y, aRect.XMost(), aRect.YMost(),
|
||||
0.0f, tl.y, br.x, br.y,
|
||||
flipped);
|
||||
return 2;
|
||||
}
|
||||
|
||||
SetRects(0, aLayerRects, aTextureRects,
|
||||
aRect.x, aRect.y, xmid, ymid,
|
||||
tl.x, tl.y, 1.0f, 1.0f,
|
||||
flipped);
|
||||
SetRects(1, aLayerRects, aTextureRects,
|
||||
xmid, aRect.y, aRect.XMost(), ymid,
|
||||
0.0f, tl.y, br.x, 1.0f,
|
||||
flipped);
|
||||
SetRects(2, aLayerRects, aTextureRects,
|
||||
aRect.x, ymid, xmid, aRect.YMost(),
|
||||
tl.x, 0.0f, 1.0f, br.y,
|
||||
flipped);
|
||||
SetRects(3, aLayerRects, aTextureRects,
|
||||
xmid, ymid, aRect.XMost(), aRect.YMost(),
|
||||
0.0f, 0.0f, br.x, br.y,
|
||||
flipped);
|
||||
return 4;
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
@ -540,6 +540,13 @@ private:
|
||||
|
||||
};
|
||||
|
||||
// Returns the number of rects. (Up to 4)
|
||||
typedef gfx::Rect decomposedRectArrayT[4];
|
||||
size_t DecomposeIntoNoRepeatRects(const gfx::Rect& aRect,
|
||||
const gfx::Rect& aTexCoordRect,
|
||||
decomposedRectArrayT* aLayerRects,
|
||||
decomposedRectArrayT* aTextureRects);
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -574,7 +574,6 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
|
||||
IntPoint origin = mCurrentRT->GetOrigin();
|
||||
mVSConstants.renderTargetOffset[0] = origin.x;
|
||||
mVSConstants.renderTargetOffset[1] = origin.y;
|
||||
mVSConstants.layerQuad = aRect;
|
||||
|
||||
mPSConstants.layerOpacity[0] = aOpacity;
|
||||
|
||||
@ -627,6 +626,7 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
|
||||
mContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
|
||||
mContext->VSSetShader(mAttachments->mVSQuadShader[maskType], nullptr, 0);
|
||||
|
||||
const Rect* pTexCoordRect = nullptr;
|
||||
|
||||
switch (aEffectChain.mPrimaryEffect->mType) {
|
||||
case EffectTypes::SOLID_COLOR: {
|
||||
@ -646,7 +646,7 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
|
||||
TexturedEffect* texturedEffect =
|
||||
static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
|
||||
|
||||
mVSConstants.textureCoords = texturedEffect->mTextureCoords;
|
||||
pTexCoordRect = &texturedEffect->mTextureCoords;
|
||||
|
||||
TextureSourceD3D11* source = texturedEffect->mTexture->AsSourceD3D11();
|
||||
|
||||
@ -682,7 +682,7 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
|
||||
|
||||
SetSamplerForFilter(Filter::LINEAR);
|
||||
|
||||
mVSConstants.textureCoords = ycbcrEffect->mTextureCoords;
|
||||
pTexCoordRect = &ycbcrEffect->mTextureCoords;
|
||||
|
||||
const int Y = 0, Cb = 1, Cr = 2;
|
||||
TextureSource* source = ycbcrEffect->mTexture;
|
||||
@ -749,7 +749,8 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
|
||||
|
||||
SetSamplerForFilter(effectComponentAlpha->mFilter);
|
||||
|
||||
mVSConstants.textureCoords = effectComponentAlpha->mTextureCoords;
|
||||
pTexCoordRect = &effectComponentAlpha->mTextureCoords;
|
||||
|
||||
RefPtr<ID3D11ShaderResourceView> views[2];
|
||||
|
||||
HRESULT hr;
|
||||
@ -774,12 +775,34 @@ CompositorD3D11::DrawQuad(const gfx::Rect& aRect,
|
||||
NS_WARNING("Unknown shader type");
|
||||
return;
|
||||
}
|
||||
if (!UpdateConstantBuffers()) {
|
||||
NS_WARNING("Failed to update shader constant buffers");
|
||||
return;
|
||||
|
||||
if (pTexCoordRect) {
|
||||
Rect layerRects[4];
|
||||
Rect textureRects[4];
|
||||
size_t rects = DecomposeIntoNoRepeatRects(aRect,
|
||||
*pTexCoordRect,
|
||||
&layerRects,
|
||||
&textureRects);
|
||||
for (size_t i = 0; i < rects; i++) {
|
||||
mVSConstants.layerQuad = layerRects[i];
|
||||
mVSConstants.textureCoords = textureRects[i];
|
||||
|
||||
if (!UpdateConstantBuffers()) {
|
||||
NS_WARNING("Failed to update shader constant buffers");
|
||||
break;
|
||||
}
|
||||
mContext->Draw(4, 0);
|
||||
}
|
||||
} else {
|
||||
mVSConstants.layerQuad = aRect;
|
||||
|
||||
if (!UpdateConstantBuffers()) {
|
||||
NS_WARNING("Failed to update shader constant buffers");
|
||||
} else {
|
||||
mContext->Draw(4, 0);
|
||||
}
|
||||
}
|
||||
|
||||
mContext->Draw(4, 0);
|
||||
if (restoreBlendMode) {
|
||||
mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF);
|
||||
}
|
||||
@ -860,7 +883,7 @@ CompositorD3D11::EndFrame()
|
||||
PaintToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mCurrentRT = nullptr;
|
||||
}
|
||||
|
||||
|
@ -383,171 +383,6 @@ CompositorOGL::Initialize()
|
||||
return true;
|
||||
}
|
||||
|
||||
static GLfloat
|
||||
WrapTexCoord(GLfloat v)
|
||||
{
|
||||
// fmodf gives negative results for negative numbers;
|
||||
// that is, fmodf(0.75, 1.0) == 0.75, but
|
||||
// fmodf(-0.75, 1.0) == -0.75. For the negative case,
|
||||
// the result we need is 0.25, so we add 1.0f.
|
||||
if (v < 0.0f) {
|
||||
return 1.0f + fmodf(v, 1.0f);
|
||||
}
|
||||
|
||||
return fmodf(v, 1.0f);
|
||||
}
|
||||
|
||||
static void
|
||||
SetRects(int n,
|
||||
Rect* aLayerRects,
|
||||
Rect* aTextureRects,
|
||||
GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
|
||||
GLfloat tx0, GLfloat ty0, GLfloat tx1, GLfloat ty1,
|
||||
bool flip_y /* = false */)
|
||||
{
|
||||
if (flip_y) {
|
||||
std::swap(ty0, ty1);
|
||||
}
|
||||
aLayerRects[n] = Rect(x0, y0, x1 - x0, y1 - y0);
|
||||
aTextureRects[n] = Rect(tx0, ty0, tx1 - tx0, ty1 - ty0);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static inline bool
|
||||
FuzzyEqual(float a, float b)
|
||||
{
|
||||
return fabs(a - b) < 0.0001f;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
DecomposeIntoNoRepeatRects(const Rect& aRect,
|
||||
const Rect& aTexCoordRect,
|
||||
Rect* aLayerRects,
|
||||
Rect* aTextureRects)
|
||||
{
|
||||
Rect texCoordRect = aTexCoordRect;
|
||||
|
||||
// If the texture should be flipped, it will have negative height. Detect that
|
||||
// here and compensate for it. We will flip each rect as we emit it.
|
||||
bool flipped = false;
|
||||
if (texCoordRect.height < 0) {
|
||||
flipped = true;
|
||||
texCoordRect.y += texCoordRect.height;
|
||||
texCoordRect.height = -texCoordRect.height;
|
||||
}
|
||||
|
||||
// Wrap the texture coordinates so they are within [0,1] and cap width/height
|
||||
// at 1. We rely on this below.
|
||||
texCoordRect = Rect(Point(WrapTexCoord(texCoordRect.x),
|
||||
WrapTexCoord(texCoordRect.y)),
|
||||
Size(std::min(texCoordRect.width, 1.0f),
|
||||
std::min(texCoordRect.height, 1.0f)));
|
||||
|
||||
NS_ASSERTION(texCoordRect.x >= 0.0f && texCoordRect.x <= 1.0f &&
|
||||
texCoordRect.y >= 0.0f && texCoordRect.y <= 1.0f &&
|
||||
texCoordRect.width >= 0.0f && texCoordRect.width <= 1.0f &&
|
||||
texCoordRect.height >= 0.0f && texCoordRect.height <= 1.0f &&
|
||||
texCoordRect.XMost() >= 0.0f && texCoordRect.XMost() <= 2.0f &&
|
||||
texCoordRect.YMost() >= 0.0f && texCoordRect.YMost() <= 2.0f,
|
||||
"We just wrapped the texture coordinates, didn't we?");
|
||||
|
||||
// Get the top left and bottom right points of the rectangle. Note that
|
||||
// tl.x/tl.y are within [0,1] but br.x/br.y are within [0,2].
|
||||
Point tl = texCoordRect.TopLeft();
|
||||
Point br = texCoordRect.BottomRight();
|
||||
|
||||
NS_ASSERTION(tl.x >= 0.0f && tl.x <= 1.0f &&
|
||||
tl.y >= 0.0f && tl.y <= 1.0f &&
|
||||
br.x >= tl.x && br.x <= 2.0f &&
|
||||
br.y >= tl.y && br.y <= 2.0f &&
|
||||
br.x - tl.x <= 1.0f &&
|
||||
br.y - tl.y <= 1.0f,
|
||||
"Somehow generated invalid texture coordinates");
|
||||
|
||||
// Then check if we wrap in either the x or y axis.
|
||||
bool xwrap = br.x > 1.0f;
|
||||
bool ywrap = br.y > 1.0f;
|
||||
|
||||
// If xwrap is false, the texture will be sampled from tl.x .. br.x.
|
||||
// If xwrap is true, then it will be split into tl.x .. 1.0, and
|
||||
// 0.0 .. WrapTexCoord(br.x). Same for the Y axis. The destination
|
||||
// rectangle is also split appropriately, according to the calculated
|
||||
// xmid/ymid values.
|
||||
if (!xwrap && !ywrap) {
|
||||
SetRects(0, aLayerRects, aTextureRects,
|
||||
aRect.x, aRect.y, aRect.XMost(), aRect.YMost(),
|
||||
tl.x, tl.y, br.x, br.y,
|
||||
flipped);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// If we are dealing with wrapping br.x and br.y are greater than 1.0 so
|
||||
// wrap them here as well.
|
||||
br = Point(xwrap ? WrapTexCoord(br.x) : br.x,
|
||||
ywrap ? WrapTexCoord(br.y) : br.y);
|
||||
|
||||
// If we wrap around along the x axis, we will draw first from
|
||||
// tl.x .. 1.0 and then from 0.0 .. br.x (which we just wrapped above).
|
||||
// The same applies for the Y axis. The midpoints we calculate here are
|
||||
// only valid if we actually wrap around.
|
||||
GLfloat xmid = aRect.x + (1.0f - tl.x) / texCoordRect.width * aRect.width;
|
||||
GLfloat ymid = aRect.y + (1.0f - tl.y) / texCoordRect.height * aRect.height;
|
||||
|
||||
NS_ASSERTION(!xwrap ||
|
||||
(xmid > aRect.x &&
|
||||
xmid < aRect.XMost() &&
|
||||
FuzzyEqual((xmid - aRect.x) + (aRect.XMost() - xmid), aRect.width)),
|
||||
"xmid should be within [x,XMost()] and the wrapped rect should have the same width");
|
||||
NS_ASSERTION(!ywrap ||
|
||||
(ymid > aRect.y &&
|
||||
ymid < aRect.YMost() &&
|
||||
FuzzyEqual((ymid - aRect.y) + (aRect.YMost() - ymid), aRect.height)),
|
||||
"ymid should be within [y,YMost()] and the wrapped rect should have the same height");
|
||||
|
||||
if (!xwrap && ywrap) {
|
||||
SetRects(0, aLayerRects, aTextureRects,
|
||||
aRect.x, aRect.y, aRect.XMost(), ymid,
|
||||
tl.x, tl.y, br.x, 1.0f,
|
||||
flipped);
|
||||
SetRects(1, aLayerRects, aTextureRects,
|
||||
aRect.x, ymid, aRect.XMost(), aRect.YMost(),
|
||||
tl.x, 0.0f, br.x, br.y,
|
||||
flipped);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (xwrap && !ywrap) {
|
||||
SetRects(0, aLayerRects, aTextureRects,
|
||||
aRect.x, aRect.y, xmid, aRect.YMost(),
|
||||
tl.x, tl.y, 1.0f, br.y,
|
||||
flipped);
|
||||
SetRects(1, aLayerRects, aTextureRects,
|
||||
xmid, aRect.y, aRect.XMost(), aRect.YMost(),
|
||||
0.0f, tl.y, br.x, br.y,
|
||||
flipped);
|
||||
return 2;
|
||||
}
|
||||
|
||||
SetRects(0, aLayerRects, aTextureRects,
|
||||
aRect.x, aRect.y, xmid, ymid,
|
||||
tl.x, tl.y, 1.0f, 1.0f,
|
||||
flipped);
|
||||
SetRects(1, aLayerRects, aTextureRects,
|
||||
xmid, aRect.y, aRect.XMost(), ymid,
|
||||
0.0f, tl.y, br.x, 1.0f,
|
||||
flipped);
|
||||
SetRects(2, aLayerRects, aTextureRects,
|
||||
aRect.x, ymid, xmid, aRect.YMost(),
|
||||
tl.x, 0.0f, 1.0f, br.y,
|
||||
flipped);
|
||||
SetRects(3, aLayerRects, aTextureRects,
|
||||
xmid, ymid, aRect.XMost(), aRect.YMost(),
|
||||
0.0f, 0.0f, br.x, br.y,
|
||||
flipped);
|
||||
return 4;
|
||||
}
|
||||
|
||||
// |aRect| is the rectangle we want to draw to. We will draw it with
|
||||
// up to 4 draw commands if necessary to avoid wrapping.
|
||||
// |aTexCoordRect| is the rectangle from the texture that we want to
|
||||
@ -562,10 +397,10 @@ CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg,
|
||||
{
|
||||
Rect layerRects[4];
|
||||
Rect textureRects[4];
|
||||
int rects = DecomposeIntoNoRepeatRects(aRect,
|
||||
aTexCoordRect,
|
||||
layerRects,
|
||||
textureRects);
|
||||
size_t rects = DecomposeIntoNoRepeatRects(aRect,
|
||||
aTexCoordRect,
|
||||
&layerRects,
|
||||
&textureRects);
|
||||
BindAndDrawQuads(aProg, rects, layerRects, textureRects);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user