Commit 80616218 by Geoff Lang Committed by Commit Bot

Support CHROMIUM_copy_texture for all formats on D3D11.

Adds a CPU readback and conversion path when the destination texture is not renderable. BUG=angleproject:1932 Change-Id: I71461ca991dc10dd636ff38e1ae20db2be0f8d63 Reviewed-on: https://chromium-review.googlesource.com/508308 Commit-Queue: Geoff Lang <geofflang@chromium.org> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org>
parent 98de826c
......@@ -366,6 +366,14 @@ void R8G8B8A8SRGB::readColor(gl::ColorF *dst, const R8G8B8A8SRGB *src)
dst->alpha = gl::normalizedToFloat(src->A);
}
void R8G8B8A8SRGB::writeColor(R8G8B8A8SRGB *dst, const gl::ColorF *src)
{
dst->R = gl::floatToNormalized<uint8_t>(src->red);
dst->G = gl::floatToNormalized<uint8_t>(src->green);
dst->B = gl::floatToNormalized<uint8_t>(src->blue);
dst->A = gl::floatToNormalized<uint8_t>(src->alpha);
}
void R8G8B8A8SRGB::average(R8G8B8A8SRGB *dst, const R8G8B8A8SRGB *src1, const R8G8B8A8SRGB *src2)
{
dst->R =
......
......@@ -165,6 +165,7 @@ struct R8G8B8A8SRGB
uint8_t A;
static void readColor(gl::ColorF *dst, const R8G8B8A8SRGB *src);
static void writeColor(R8G8B8A8SRGB *dst, const gl::ColorF *src);
static void average(R8G8B8A8SRGB *dst, const R8G8B8A8SRGB *src1, const R8G8B8A8SRGB *src2);
};
......
// GENERATED FILE - DO NOT EDIT.
// Generated by gen_copy_conversion_table.py using data from es3_copy_conversion_formats.json.
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
......
......@@ -28,6 +28,7 @@ struct Format final : private angle::NonCopyable
rx::MipGenerationFunction mipGen,
const rx::FastCopyFunctionMap &fastCopyFunctions,
rx::ColorReadFunction colorRead,
rx::ColorWriteFunction colorWrite,
GLenum componentType,
GLuint redBits,
GLuint greenBits,
......@@ -51,6 +52,7 @@ struct Format final : private angle::NonCopyable
rx::MipGenerationFunction mipGenerationFunction;
rx::ColorReadFunction colorReadFunction;
rx::ColorWriteFunction colorWriteFunction;
// A map from a gl::FormatType to a fast pixel copy function for this format.
const rx::FastCopyFunctionMap &fastCopyFunctions;
......@@ -71,6 +73,7 @@ constexpr Format::Format(ID id,
rx::MipGenerationFunction mipGen,
const rx::FastCopyFunctionMap &fastCopyFunctions,
rx::ColorReadFunction colorRead,
rx::ColorWriteFunction colorWrite,
GLenum componentType,
GLuint redBits,
GLuint greenBits,
......@@ -83,6 +86,7 @@ constexpr Format::Format(ID id,
fboImplementationInternalFormat(fboFormat),
mipGenerationFunction(mipGen),
colorReadFunction(colorRead),
colorWriteFunction(colorWrite),
fastCopyFunctions(fastCopyFunctions),
componentType(componentType),
redBits(redBits),
......
// GENERATED FILE - DO NOT EDIT.
// Generated by gen_angle_format_table.py using data from angle_format_data.json
//
// Copyright 2016 The ANGLE Project Authors. All rights reserved.
// Copyright 2017 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
......
......@@ -217,6 +217,13 @@ class RendererD3D : public BufferFactoryD3D
virtual gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) = 0;
virtual gl::Error generateMipmapUsingD3D(TextureStorage *storage,
const gl::TextureState &textureState) = 0;
virtual gl::Error copyImage(ImageD3D *dest,
ImageD3D *source,
const gl::Rectangle &sourceRect,
const gl::Offset &destOffset,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha) = 0;
virtual TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) = 0;
virtual TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage,
RenderTargetD3D *renderTargetD3D) = 0;
......
......@@ -100,6 +100,18 @@ gl::Error TextureD3D::getNativeTexture(TextureStorage **outStorage)
return gl::NoError();
}
gl::Error TextureD3D::getImageAndSyncFromStorage(const gl::ImageIndex &index,
ImageD3D **outImage) const
{
ImageD3D *image = getImage(index);
if (mTexStorage)
{
ANGLE_TRY(image->copyFromTexStorage(index, mTexStorage));
}
*outImage = image;
return gl::NoError();
}
GLint TextureD3D::getLevelZeroWidth() const
{
ASSERT(gl::CountLeadingZeros(static_cast<uint32_t>(getBaseLevelWidth())) > getBaseLevel());
......@@ -1053,14 +1065,15 @@ gl::Error TextureD3D_2D::copyTexture(ContextImpl *contextImpl,
static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
redefineImage(destLevel, internalFormatInfo.sizedInternalFormat, size, false);
gl::Rectangle sourceRect(0, 0, size.width, size.height);
gl::Offset destOffset(0, 0, 0);
if (canCreateRenderTargetForImage(gl::ImageIndex::Make2D(destLevel)))
{
ANGLE_TRY(ensureRenderTarget());
ASSERT(isValidLevel(destLevel));
ANGLE_TRY(updateStorageLevel(destLevel));
gl::Rectangle sourceRect(0, 0, size.width, size.height);
gl::Offset destOffset(0, 0, 0);
ANGLE_TRY(mRenderer->copyTexture(source, static_cast<GLint>(sourceLevel), sourceRect,
internalFormatInfo.format, destOffset, mTexStorage, target,
destLevel, unpackFlipY, unpackPremultiplyAlpha,
......@@ -1068,8 +1081,17 @@ gl::Error TextureD3D_2D::copyTexture(ContextImpl *contextImpl,
}
else
{
ASSERT(internalFormat == GL_RGB9_E5);
UNIMPLEMENTED();
gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel));
TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
ImageD3D *sourceImage = nullptr;
ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(sourceImageIndex, &sourceImage));
gl::ImageIndex destImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(destLevel));
ImageD3D *destImage = nullptr;
ANGLE_TRY(getImageAndSyncFromStorage(destImageIndex, &destImage));
ANGLE_TRY(mRenderer->copyImage(destImage, sourceImage, sourceRect, destOffset, unpackFlipY,
unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
}
return gl::NoError();
......@@ -1103,8 +1125,17 @@ gl::Error TextureD3D_2D::copySubTexture(ContextImpl *contextImpl,
}
else
{
ASSERT(getInternalFormat(destLevel) == GL_RGB9_E5);
UNIMPLEMENTED();
gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel));
TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
ImageD3D *sourceImage = nullptr;
ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(sourceImageIndex, &sourceImage));
gl::ImageIndex destImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(destLevel));
ImageD3D *destImage = nullptr;
ANGLE_TRY(getImageAndSyncFromStorage(destImageIndex, &destImage));
ANGLE_TRY(mRenderer->copyImage(destImage, sourceImage, sourceArea, destOffset, unpackFlipY,
unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
}
return gl::NoError();
......@@ -1747,14 +1778,15 @@ gl::Error TextureD3D_Cube::copyTexture(ContextImpl *contextImpl,
static_cast<int>(source->getHeight(sourceTarget, sourceLevel)), 1);
redefineImage(faceIndex, destLevel, internalFormatInfo.sizedInternalFormat, size);
gl::Rectangle sourceRect(0, 0, size.width, size.height);
gl::Offset destOffset(0, 0, 0);
if (canCreateRenderTargetForImage(gl::ImageIndex::MakeCube(target, destLevel)))
{
ANGLE_TRY(ensureRenderTarget());
ASSERT(isValidFaceLevel(faceIndex, destLevel));
ANGLE_TRY(updateStorageFaceLevel(faceIndex, destLevel));
gl::Rectangle sourceRect(0, 0, size.width, size.height);
gl::Offset destOffset(0, 0, 0);
ANGLE_TRY(mRenderer->copyTexture(source, static_cast<GLint>(sourceLevel), sourceRect,
internalFormatInfo.format, destOffset, mTexStorage, target,
destLevel, unpackFlipY, unpackPremultiplyAlpha,
......@@ -1762,8 +1794,18 @@ gl::Error TextureD3D_Cube::copyTexture(ContextImpl *contextImpl,
}
else
{
ASSERT(internalFormat == GL_RGB9_E5);
UNIMPLEMENTED();
gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel));
TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
ImageD3D *sourceImage = nullptr;
ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(sourceImageIndex, &sourceImage));
gl::ImageIndex destImageIndex =
gl::ImageIndex::MakeCube(target, static_cast<GLint>(destLevel));
ImageD3D *destImage = nullptr;
ANGLE_TRY(getImageAndSyncFromStorage(destImageIndex, &destImage));
ANGLE_TRY(mRenderer->copyImage(destImage, sourceImage, sourceRect, destOffset, unpackFlipY,
unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
}
return gl::NoError();
......@@ -1798,8 +1840,18 @@ gl::Error TextureD3D_Cube::copySubTexture(ContextImpl *contextImpl,
}
else
{
ASSERT(getInternalFormat(destLevel, faceIndex) == GL_RGB9_E5);
UNIMPLEMENTED();
gl::ImageIndex sourceImageIndex = gl::ImageIndex::Make2D(static_cast<GLint>(sourceLevel));
TextureD3D *sourceD3D = GetImplAs<TextureD3D>(source);
ImageD3D *sourceImage = nullptr;
ANGLE_TRY(sourceD3D->getImageAndSyncFromStorage(sourceImageIndex, &sourceImage));
gl::ImageIndex destImageIndex =
gl::ImageIndex::MakeCube(target, static_cast<GLint>(destLevel));
ImageD3D *destImage = nullptr;
ANGLE_TRY(getImageAndSyncFromStorage(destImageIndex, &destImage));
ANGLE_TRY(mRenderer->copyImage(destImage, sourceImage, sourceArea, destOffset, unpackFlipY,
unpackPremultiplyAlpha, unpackUnmultiplyAlpha));
}
return gl::NoError();
......
......@@ -41,6 +41,8 @@ class TextureD3D : public TextureImpl
virtual ImageD3D *getImage(const gl::ImageIndex &index) const = 0;
virtual GLsizei getLayerCount(int level) const = 0;
gl::Error getImageAndSyncFromStorage(const gl::ImageIndex &index, ImageD3D **outImage) const;
GLint getBaseLevelWidth() const;
GLint getBaseLevelHeight() const;
GLenum getBaseLevelInternalFormat() const;
......
......@@ -23,6 +23,50 @@
namespace rx
{
namespace
{
void CopyColor(gl::ColorF *color)
{
// No-op
}
void PremultiplyAlpha(gl::ColorF *color)
{
color->red *= color->alpha;
color->green *= color->alpha;
color->blue *= color->alpha;
}
void UnmultiplyAlpha(gl::ColorF *color)
{
if (color->alpha != 0.0f)
{
float invAlpha = 1.0f / color->alpha;
color->red *= invAlpha;
color->green *= invAlpha;
color->blue *= invAlpha;
}
}
void WriteUintColor(const gl::ColorF &color,
ColorWriteFunction colorWriteFunction,
uint8_t *destPixelData)
{
gl::ColorUI destColor(
static_cast<unsigned int>(color.red * 255), static_cast<unsigned int>(color.green * 255),
static_cast<unsigned int>(color.red * 255), static_cast<unsigned int>(color.alpha * 255));
colorWriteFunction(reinterpret_cast<const uint8_t *>(&destColor), destPixelData);
}
void WriteFloatColor(const gl::ColorF &color,
ColorWriteFunction colorWriteFunction,
uint8_t *destPixelData)
{
colorWriteFunction(reinterpret_cast<const uint8_t *>(&color), destPixelData);
}
} // anonymous namespace
Image11::Image11(Renderer11 *renderer)
: mRenderer(renderer),
mDXGIFormat(DXGI_FORMAT_UNKNOWN),
......@@ -77,6 +121,97 @@ gl::Error Image11::generateMipmap(Image11 *dest,
return gl::NoError();
}
gl::Error Image11::copyImage(Image11 *dest,
Image11 *source,
const gl::Rectangle &sourceRect,
const gl::Offset &destOffset,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const Renderer11DeviceCaps &rendererCaps)
{
D3D11_MAPPED_SUBRESOURCE destMapped;
ANGLE_TRY(dest->map(D3D11_MAP_WRITE, &destMapped));
D3D11_MAPPED_SUBRESOURCE srcMapped;
gl::Error error = source->map(D3D11_MAP_READ, &srcMapped);
if (error.isError())
{
dest->unmap();
return error;
}
const auto &sourceFormat =
d3d11::Format::Get(source->getInternalFormat(), rendererCaps).format();
GLuint sourcePixelBytes =
gl::GetSizedInternalFormatInfo(sourceFormat.fboImplementationInternalFormat).pixelBytes;
const auto &destFormat = d3d11::Format::Get(dest->getInternalFormat(), rendererCaps).format();
const auto &destFormatInfo =
gl::GetSizedInternalFormatInfo(destFormat.fboImplementationInternalFormat);
GLuint destPixelBytes = destFormatInfo.pixelBytes;
const uint8_t *sourceData = reinterpret_cast<const uint8_t *>(srcMapped.pData);
uint8_t *destData = reinterpret_cast<uint8_t *>(destMapped.pData);
using ConversionFunction = void (*)(gl::ColorF *);
ConversionFunction conversionFunction = CopyColor;
if (unpackPremultiplyAlpha != unpackUnmultiplyAlpha)
{
if (unpackPremultiplyAlpha)
{
conversionFunction = PremultiplyAlpha;
}
else
{
conversionFunction = UnmultiplyAlpha;
}
}
auto writeFunction =
(destFormatInfo.componentType == GL_UNSIGNED_INT) ? WriteUintColor : WriteFloatColor;
for (int y = 0; y < sourceRect.height; y++)
{
for (int x = 0; x < sourceRect.width; x++)
{
int sourceX = sourceRect.x + x;
int sourceY = sourceRect.y + y;
const uint8_t *sourcePixelData =
sourceData + sourceY * srcMapped.RowPitch + sourceX * sourcePixelBytes;
gl::ColorF sourceColor;
sourceFormat.colorReadFunction(sourcePixelData,
reinterpret_cast<uint8_t *>(&sourceColor));
conversionFunction(&sourceColor);
int destX = destOffset.x + x;
int destY = destOffset.y;
if (unpackFlipY)
{
destY += (sourceRect.height - 1);
destY -= y;
}
else
{
destY += y;
}
uint8_t *destPixelData =
destData + destY * destMapped.RowPitch + destX * destPixelBytes;
writeFunction(sourceColor, destFormat.colorWriteFunction, destPixelData);
}
}
dest->unmap();
source->unmap();
dest->markDirty();
return gl::NoError();
}
bool Image11::isDirty() const
{
// If mDirty is true AND mStagingTexture doesn't exist AND mStagingTexture doesn't need to be
......
......@@ -36,6 +36,14 @@ class Image11 : public ImageD3D
static gl::Error generateMipmap(Image11 *dest,
Image11 *src,
const Renderer11DeviceCaps &rendererCaps);
static gl::Error copyImage(Image11 *dest,
Image11 *source,
const gl::Rectangle &sourceRect,
const gl::Offset &destOffset,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const Renderer11DeviceCaps &rendererCaps);
virtual bool isDirty() const;
......
......@@ -3966,6 +3966,20 @@ gl::Error Renderer11::generateMipmapUsingD3D(TextureStorage *storage,
return gl::NoError();
}
gl::Error Renderer11::copyImage(ImageD3D *dest,
ImageD3D *source,
const gl::Rectangle &sourceRect,
const gl::Offset &destOffset,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha)
{
Image11 *dest11 = GetAs<Image11>(dest);
Image11 *src11 = GetAs<Image11>(source);
return Image11::copyImage(dest11, src11, sourceRect, destOffset, unpackFlipY,
unpackPremultiplyAlpha, unpackUnmultiplyAlpha, mRenderer11DeviceCaps);
}
TextureStorage *Renderer11::createTextureStorage2D(SwapChainD3D *swapChain)
{
SwapChain11 *swapChain11 = GetAs<SwapChain11>(swapChain);
......
......@@ -262,6 +262,13 @@ class Renderer11 : public RendererD3D
gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override;
gl::Error generateMipmapUsingD3D(TextureStorage *storage,
const gl::TextureState &textureState) override;
gl::Error copyImage(ImageD3D *dest,
ImageD3D *source,
const gl::Rectangle &sourceRect,
const gl::Offset &destOffset,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha) override;
TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) override;
TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage,
RenderTargetD3D *renderTargetD3D) override;
......
......@@ -2925,6 +2925,18 @@ gl::Error Renderer9::generateMipmapUsingD3D(TextureStorage *storage,
return gl::NoError();
}
gl::Error Renderer9::copyImage(ImageD3D *dest,
ImageD3D *source,
const gl::Rectangle &sourceRect,
const gl::Offset &destOffset,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha)
{
UNREACHABLE();
return gl::NoError();
}
TextureStorage *Renderer9::createTextureStorage2D(SwapChainD3D *swapChain)
{
SwapChain9 *swapChain9 = GetAs<SwapChain9>(swapChain);
......
......@@ -266,6 +266,13 @@ class Renderer9 : public RendererD3D
gl::Error generateMipmap(ImageD3D *dest, ImageD3D *source) override;
gl::Error generateMipmapUsingD3D(TextureStorage *storage,
const gl::TextureState &textureState) override;
gl::Error copyImage(ImageD3D *dest,
ImageD3D *source,
const gl::Rectangle &sourceRect,
const gl::Offset &destOffset,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha) override;
TextureStorage *createTextureStorage2D(SwapChainD3D *swapChain) override;
TextureStorage *createTextureStorageEGLImage(EGLImageD3D *eglImage,
RenderTargetD3D *renderTargetD3D) override;
......
......@@ -61,7 +61,7 @@ static constexpr rx::FastCopyFunctionMap NoCopyFunctions;
constexpr Format g_formatInfoTable[] = {{
// clang-format off
{{ Format::ID::NONE, GL_NONE, GL_NONE, nullptr, NoCopyFunctions, nullptr, GL_NONE, 0, 0, 0, 0, 0, 0 }},
{{ Format::ID::NONE, GL_NONE, GL_NONE, nullptr, NoCopyFunctions, nullptr, nullptr, GL_NONE, 0, 0, 0, 0, 0, 0 }},
{angle_format_info_cases} // clang-format on
}};
......@@ -110,10 +110,7 @@ def get_mip_generation_function(angle_format):
return 'nullptr'
return 'GenerateMip<' + channel_struct + '>'
def get_color_read_function(angle_format):
channel_struct = get_channel_struct(angle_format)
if channel_struct == None:
return 'nullptr'
def get_color_read_write_component_type(angle_format):
component_type_map = {
'uint': 'GLuint',
'int': 'GLint',
......@@ -121,9 +118,24 @@ def get_color_read_function(angle_format):
'snorm': 'GLfloat',
'float': 'GLfloat'
}
return 'ReadColor<' + channel_struct + ', '+ component_type_map[angle_format['componentType']] + '>'
return component_type_map[angle_format['componentType']]
def get_color_read_function(angle_format):
channel_struct = get_channel_struct(angle_format)
if channel_struct == None:
return 'nullptr'
read_component_type = get_color_read_write_component_type(angle_format)
return 'ReadColor<' + channel_struct + ', '+ read_component_type + '>'
def get_color_write_function(angle_format):
channel_struct = get_channel_struct(angle_format)
if channel_struct == None:
return 'nullptr'
write_component_type = get_color_read_write_component_type(angle_format)
return 'WriteColor<' + channel_struct + ', '+ write_component_type + '>'
format_entry_template = """ {{ Format::ID::{id}, {glInternalFormat}, {fboImplementationInternalFormat}, {mipGenerationFunction}, {fastCopyFunctions}, {colorReadFunction}, {namedComponentType}, {R}, {G}, {B}, {A}, {D}, {S} }},
format_entry_template = """ {{ Format::ID::{id}, {glInternalFormat}, {fboImplementationInternalFormat}, {mipGenerationFunction}, {fastCopyFunctions}, {colorReadFunction}, {colorWriteFunction}, {namedComponentType}, {R}, {G}, {B}, {A}, {D}, {S} }},
"""
def get_named_component_type(component_type):
......@@ -172,6 +184,7 @@ def json_to_table_data(format_id, json, angle_to_gl):
# Derived values.
parsed["mipGenerationFunction"] = get_mip_generation_function(parsed)
parsed["colorReadFunction"] = get_color_read_function(parsed)
parsed["colorWriteFunction"] = get_color_write_function(parsed)
for channel in "ABDGLRS":
if parsed["bits"] != None and channel in parsed["bits"]:
......
......@@ -927,7 +927,7 @@ TEST_P(CopyTextureTestES3, ES3FloatFormats)
GL_R11F_G11F_B10F, GL_FLOAT, false, false, true,
GLColor32F(1.0f, 0.5f, 0.25f, 1.0f));
if (IsD3D11() || IsOpenGL() || IsOpenGLES())
if (IsOpenGL() || IsOpenGLES())
{
std::cout << "Skipping GL_RGB9_E5 because it is not implemented yet." << std::endl;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment