Metal: Implement GL_OES_texture_3D

Bug: angleproject:2634
Change-Id: I8c46493ac28fe1bbfdb29ee3a60b23076bbc4c0c
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2336119
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Jonah Ryan-Davis <jonahr@google.com>
This commit is contained in:
Le Hoang Quyen 2020-08-08 18:36:57 +08:00 коммит произвёл Commit Bot
Родитель f2196ad676
Коммит acda9ddea1
16 изменённых файлов: 1450 добавлений и 435 удалений

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

@ -133,7 +133,7 @@ angle::Result ContextMtl::ensureIncompleteTexturesCreated(const gl::Context *con
{
return angle::Result::Continue;
}
constexpr gl::TextureType supportedTextureTypes[] = {gl::TextureType::_2D,
constexpr gl::TextureType supportedTextureTypes[] = {gl::TextureType::_2D, gl::TextureType::_3D,
gl::TextureType::CubeMap};
for (gl::TextureType texType : supportedTextureTypes)
{

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

@ -639,7 +639,7 @@ void DisplayMtl::initializeExtensions() const
mNativeExtensions.textureNPOTOES = true;
mNativeExtensions.texture3DOES = false;
mNativeExtensions.texture3DOES = true;
mNativeExtensions.standardDerivativesOES = true;

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

@ -1069,17 +1069,17 @@ angle::Result FramebufferMtl::readPixelsImpl(const gl::Context *context,
return angle::Result::Continue;
}
mtl::Texture *texture;
mtl::TextureRef texture;
if (mBackbuffer)
{
// Backbuffer might have MSAA texture as render target, needs to obtain the
// resolved texture to be able to read pixels.
ANGLE_TRY(mBackbuffer->ensureColorTextureReadyForReadPixels(context));
texture = mBackbuffer->getColorTexture().get();
texture = mBackbuffer->getColorTexture();
}
else
{
texture = renderTarget->getTexture().get();
texture = renderTarget->getTexture();
// For non-default framebuffer, MSAA read pixels is disallowed.
ANGLE_MTL_CHECK(contextMtl, texture->samples() == 1, GL_INVALID_OPERATION);
}
@ -1087,13 +1087,12 @@ angle::Result FramebufferMtl::readPixelsImpl(const gl::Context *context,
const mtl::Format &readFormat = *renderTarget->getFormat();
const angle::Format &readAngleFormat = readFormat.actualAngleFormat();
// NOTE(hqle): resolve MSAA texture before readback
int srcRowPitch = area.width * readAngleFormat.pixelBytes;
int bufferRowPitch = area.width * readAngleFormat.pixelBytes;
angle::MemoryBuffer readPixelRowBuffer;
ANGLE_CHECK_GL_ALLOC(contextMtl, readPixelRowBuffer.resize(srcRowPitch));
ANGLE_CHECK_GL_ALLOC(contextMtl, readPixelRowBuffer.resize(bufferRowPitch));
auto packPixelsRowParams = packPixelsParams;
MTLRegion mtlSrcRowRegion = MTLRegionMake2D(area.x, area.y, area.width, 1);
auto packPixelsRowParams = packPixelsParams;
gl::Rectangle srcRowRegion(area.x, area.y, area.width, 1);
int rowOffset = packPixelsParams.reverseRowOrder ? -1 : 1;
int startRow = packPixelsParams.reverseRowOrder ? (area.y1() - 1) : area.y;
@ -1104,16 +1103,16 @@ angle::Result FramebufferMtl::readPixelsImpl(const gl::Context *context,
for (int r = startRow, i = 0; i < area.height;
++i, r += rowOffset, pixels += packPixelsRowParams.outputPitch)
{
mtlSrcRowRegion.origin.y = r;
srcRowRegion.y = r;
packPixelsRowParams.area.y = packPixelsParams.area.y + i;
// Read the pixels data to the row buffer
texture->getBytes(contextMtl, srcRowPitch, mtlSrcRowRegion,
static_cast<uint32_t>(renderTarget->getLevelIndex()),
readPixelRowBuffer.data());
ANGLE_TRY(mtl::ReadTexturePerSliceBytes(
context, texture, bufferRowPitch, srcRowRegion, renderTarget->getLevelIndex(),
renderTarget->getLayerIndex(), readPixelRowBuffer.data()));
// Convert to destination format
PackPixels(packPixelsRowParams, readAngleFormat, srcRowPitch, readPixelRowBuffer.data(),
PackPixels(packPixelsRowParams, readAngleFormat, bufferRowPitch, readPixelRowBuffer.data(),
pixels);
}

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

@ -21,6 +21,13 @@
namespace rx
{
// structure represents one image definition of a texture created by glTexImage* call.
struct ImageDefinitionMtl
{
mtl::TextureRef image;
angle::FormatID formatID = angle::FormatID::NONE;
};
class TextureMtl : public TextureImpl
{
public:
@ -162,12 +169,25 @@ class TextureMtl : public TextureImpl
private:
void releaseTexture(bool releaseImages);
void releaseTexture(bool releaseImages, bool releaseTextureObjectsOnly);
angle::Result createNativeTexture(const gl::Context *context,
gl::TextureType type,
GLuint mips,
const gl::Extents &size);
angle::Result ensureSamplerStateCreated(const gl::Context *context);
// Ensure image at given index is created:
angle::Result ensureImageCreated(const gl::Context *context, const gl::ImageIndex &index);
// Ensure all image views at all faces/levels are retained.
void retainImageDefinitions();
mtl::TextureRef createImageViewFromNativeTexture(GLuint cubeFaceOrZero, GLuint nativeLevel);
angle::Result checkForEmulatedChannels(const gl::Context *context,
const mtl::Format &mtlFormat,
const mtl::TextureRef &texture);
int getNativeLevel(const gl::ImageIndex &imageIndex) const;
mtl::TextureRef &getImage(const gl::ImageIndex &imageIndex);
ImageDefinitionMtl &getImageDefinition(const gl::ImageIndex &imageIndex);
RenderTargetMtl &getRenderTarget(const gl::ImageIndex &imageIndex);
bool isIndexWithinMinMaxLevels(const gl::ImageIndex &imageIndex) const;
// If levels = 0, this function will create full mipmaps texture.
angle::Result setStorageImpl(const gl::Context *context,
@ -183,10 +203,12 @@ class TextureMtl : public TextureImpl
angle::Result setImageImpl(const gl::Context *context,
const gl::ImageIndex &index,
const gl::InternalFormat &formatInfo,
const gl::InternalFormat &dstFormatInfo,
const gl::Extents &size,
GLenum type,
GLenum srcFormat,
GLenum srcType,
const gl::PixelUnpackState &unpack,
gl::Buffer *unpackBuffer,
const uint8_t *pixels);
angle::Result setSubImageImpl(const gl::Context *context,
const gl::ImageIndex &index,
@ -194,6 +216,7 @@ class TextureMtl : public TextureImpl
const gl::InternalFormat &formatInfo,
GLenum type,
const gl::PixelUnpackState &unpack,
gl::Buffer *unpackBuffer,
const uint8_t *pixels);
angle::Result copySubImageImpl(const gl::Context *context,
@ -250,15 +273,33 @@ class TextureMtl : public TextureImpl
bool unpackUnmultiplyAlpha,
const mtl::TextureRef &sourceTexture);
// Copy data to texture's per array's slice/cube's face. NOTE: This function doesn't upload
// data to 3D texture's z layer. Metal treats 3D texture's z layer & array texture's slice
// differently. For array/cube texture, it is only possible to upload to one slice at a time.
angle::Result setPerSliceSubImage(const gl::Context *context,
int slice,
const MTLRegion &mtlArea,
const gl::InternalFormat &internalFormat,
GLenum type,
const angle::Format &pixelsAngleFormat,
size_t pixelsRowPitch,
size_t pixelsDepthPitch,
gl::Buffer *unpackBuffer,
const uint8_t *pixels,
const mtl::TextureRef &image);
// Convert pixels to suported format before uploading to texture
angle::Result convertAndSetSubImage(const gl::Context *context,
const gl::ImageIndex &index,
const MTLRegion &mtlArea,
const gl::InternalFormat &internalFormat,
GLenum type,
const angle::Format &pixelsFormat,
size_t pixelsRowPitch,
const uint8_t *pixels);
angle::Result convertAndSetPerSliceSubImage(const gl::Context *context,
int slice,
const MTLRegion &mtlArea,
const gl::InternalFormat &internalFormat,
GLenum type,
const angle::Format &pixelsAngleFormat,
size_t pixelsRowPitch,
size_t pixelsDepthPitch,
gl::Buffer *unpackBuffer,
const uint8_t *pixels,
const mtl::TextureRef &image);
angle::Result generateMipmapCPU(const gl::Context *context);
@ -267,12 +308,23 @@ class TextureMtl : public TextureImpl
mtl::TextureRef mNativeTexture;
id<MTLSamplerState> mMetalSamplerState = nil;
std::vector<RenderTargetMtl> mLayeredRenderTargets;
std::vector<mtl::TextureRef> mLayeredTextureViews;
// Number of slices
uint32_t mSlices = 1;
// Stored images array defined by glTexImage/glCopy*.
// Once the images array is complete, they will be transferred to real texture object.
std::map<int, gl::TexLevelArray<mtl::TextureRef>> mTexImages;
// NOTE:
// - For Cube map, there will be at most 6 entries in the mTexImageDefs table, one for each
// face. This is because the Cube map's image is defined per face & per level.
// - For other texture types, there will be only one entry in the map table. All other textures
// except Cube map has texture image defined per level (all slices included).
std::map<int, gl::TexLevelArray<ImageDefinitionMtl>> mTexImageDefs;
// Render Target per slice/depth/cube face.
// - For 2D texture: There will be one key entry in the map.
// - For Cube map: There will be at most 6 key entries.
// - For array/3D texture: There will be at most slices/depths number of key entries.
std::map<int, gl::TexLevelArray<RenderTargetMtl>> mPerLayerRenderTargets;
bool mIsPow2 = false;
};

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -491,12 +491,11 @@ class BlitCommandEncoder final : public CommandEncoder
BlitCommandEncoder &copyTexture(const TextureRef &src,
uint32_t srcSlice,
uint32_t srcLevel,
MTLOrigin srcOrigin,
MTLSize srcSize,
const TextureRef &dst,
uint32_t dstSlice,
uint32_t dstLevel,
MTLOrigin dstOrigin);
uint32_t sliceCount,
uint32_t levelCount);
BlitCommandEncoder &generateMipmapsForTexture(const TextureRef &texture);
BlitCommandEncoder &synchronizeResource(const TextureRef &texture);

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

@ -1534,14 +1534,13 @@ BlitCommandEncoder &BlitCommandEncoder::copyBufferToTexture(const BufferRef &src
}
BlitCommandEncoder &BlitCommandEncoder::copyTexture(const TextureRef &src,
uint32_t srcSlice,
uint32_t srcLevel,
MTLOrigin srcOrigin,
MTLSize srcSize,
uint32_t srcStartSlice,
uint32_t srcStartLevel,
const TextureRef &dst,
uint32_t dstSlice,
uint32_t dstLevel,
MTLOrigin dstOrigin)
uint32_t dstStartSlice,
uint32_t dstStartLevel,
uint32_t sliceCount,
uint32_t levelCount)
{
if (!src || !dst)
{
@ -1550,15 +1549,30 @@ BlitCommandEncoder &BlitCommandEncoder::copyTexture(const TextureRef &src,
cmdBuffer().setReadDependency(src);
cmdBuffer().setWriteDependency(dst);
[get() copyFromTexture:src->get()
sourceSlice:srcSlice
sourceLevel:srcLevel
sourceOrigin:srcOrigin
sourceSize:srcSize
toTexture:dst->get()
destinationSlice:dstSlice
destinationLevel:dstLevel
destinationOrigin:dstOrigin];
MTLOrigin origin = MTLOriginMake(0, 0, 0);
for (uint32_t slice = 0; slice < sliceCount; ++slice)
{
uint32_t srcSlice = srcStartSlice + slice;
uint32_t dstSlice = dstStartSlice + slice;
for (uint32_t level = 0; level < levelCount; ++level)
{
uint32_t srcLevel = srcStartLevel + level;
uint32_t dstLevel = dstStartLevel + level;
MTLSize srcSize =
MTLSizeMake(src->width(srcLevel), src->height(srcLevel), src->depth(srcLevel));
[get() copyFromTexture:src->get()
sourceSlice:srcSlice
sourceLevel:srcLevel
sourceOrigin:origin
sourceSize:srcSize
toTexture:dst->get()
destinationSlice:dstSlice
destinationLevel:dstLevel
destinationOrigin:origin];
}
}
return *this;
}

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

@ -120,6 +120,16 @@ class Texture final : public Resource,
bool allowFormatView,
TextureRef *refOut);
static angle::Result Make3DTexture(ContextMtl *context,
const Format &format,
uint32_t width,
uint32_t height,
uint32_t depth,
uint32_t mips,
bool renderTargetOnly,
bool allowFormatView,
TextureRef *refOut);
static TextureRef MakeFromMetal(id<MTLTexture> metalTexture);
// Allow CPU to read & write data directly to this texture?
@ -127,24 +137,35 @@ class Texture final : public Resource,
bool supportFormatView() const;
void replace2DRegion(ContextMtl *context,
const MTLRegion &region,
uint32_t mipmapLevel,
uint32_t slice,
const uint8_t *data,
size_t bytesPerRow);
void replaceRegion(ContextMtl *context,
MTLRegion region,
const MTLRegion &region,
uint32_t mipmapLevel,
uint32_t slice,
const uint8_t *data,
size_t bytesPerRow);
size_t bytesPerRow,
size_t bytesPer2DImage);
// read pixel data from slice 0
void getBytes(ContextMtl *context,
size_t bytesPerRow,
MTLRegion region,
size_t bytesPer2DInage,
const MTLRegion &region,
uint32_t mipmapLevel,
uint32_t slice,
uint8_t *dataOut);
// Create 2d view of a cube face which full range of mip levels.
TextureRef createCubeFaceView(uint32_t face);
// Create a view of one slice at a level.
TextureRef createSliceMipView(uint32_t slice, uint32_t level);
// Create a view of a level.
TextureRef createMipView(uint32_t level);
// Create a view with different format
TextureRef createViewWithDifferentFormat(MTLPixelFormat format);
// Same as above but the target format must be compatible, for example sRGB to linear. In this
@ -155,6 +176,8 @@ class Texture final : public Resource,
MTLPixelFormat pixelFormat() const;
uint32_t mipmapLevels() const;
uint32_t arrayLength() const;
uint32_t cubeFacesOrArrayLength() const;
uint32_t width(uint32_t level = 0) const;
uint32_t height(uint32_t level = 0) const;
@ -201,7 +224,7 @@ class Texture final : public Resource,
// Create a texture view
Texture(Texture *original, MTLPixelFormat format);
Texture(Texture *original, MTLTextureType type, NSRange mipmapLevelRange, uint32_t slice);
Texture(Texture *original, MTLTextureType type, NSRange mipmapLevelRange, NSRange slices);
void syncContent(ContextMtl *context);

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

@ -148,6 +148,37 @@ angle::Result Texture::Make2DMSTexture(ContextMtl *context,
} // ANGLE_MTL_OBJC_SCOPE
}
/** static */
angle::Result Texture::Make3DTexture(ContextMtl *context,
const Format &format,
uint32_t width,
uint32_t height,
uint32_t depth,
uint32_t mips,
bool renderTargetOnly,
bool allowFormatView,
TextureRef *refOut)
{
ANGLE_MTL_OBJC_SCOPE
{
// Use texture2DDescriptorWithPixelFormat to calculate full range mipmap range:
uint32_t maxDimen = std::max(width, height);
maxDimen = std::max(maxDimen, depth);
MTLTextureDescriptor *desc =
[MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format.metalFormat
width:maxDimen
height:maxDimen
mipmapped:mips == 0 || mips > 1];
desc.textureType = MTLTextureType3D;
desc.width = width;
desc.height = height;
desc.depth = depth;
return MakeTexture(context, format, desc, mips, renderTargetOnly, allowFormatView, refOut);
} // ANGLE_MTL_OBJC_SCOPE
}
/** static */
angle::Result Texture::MakeTexture(ContextMtl *context,
const Format &mtlFormat,
@ -242,7 +273,7 @@ Texture::Texture(Texture *original, MTLPixelFormat format)
}
}
Texture::Texture(Texture *original, MTLTextureType type, NSRange mipmapLevelRange, uint32_t slice)
Texture::Texture(Texture *original, MTLTextureType type, NSRange mipmapLevelRange, NSRange slices)
: Resource(original),
mColorWritableMask(original->mColorWritableMask) // Share color write mask property
{
@ -251,7 +282,7 @@ Texture::Texture(Texture *original, MTLTextureType type, NSRange mipmapLevelRang
auto view = [original->get() newTextureViewWithPixelFormat:original->pixelFormat()
textureType:type
levels:mipmapLevelRange
slices:NSMakeRange(slice, 1)];
slices:slices];
set([view ANGLE_MTL_AUTORELEASE]);
}
@ -299,12 +330,24 @@ bool Texture::supportFormatView() const
return get().usage & MTLTextureUsagePixelFormatView;
}
void Texture::replace2DRegion(ContextMtl *context,
const MTLRegion &region,
uint32_t mipmapLevel,
uint32_t slice,
const uint8_t *data,
size_t bytesPerRow)
{
ASSERT(region.size.depth == 1);
replaceRegion(context, region, mipmapLevel, slice, data, bytesPerRow, 0);
}
void Texture::replaceRegion(ContextMtl *context,
MTLRegion region,
const MTLRegion &region,
uint32_t mipmapLevel,
uint32_t slice,
const uint8_t *data,
size_t bytesPerRow)
size_t bytesPerRow,
size_t bytesPer2DImage)
{
if (mipmapLevel >= this->mipmapLevels())
{
@ -325,18 +368,25 @@ void Texture::replaceRegion(ContextMtl *context,
cmdQueue.ensureResourceReadyForCPU(this);
if (textureType() != MTLTextureType3D)
{
bytesPer2DImage = 0;
}
[get() replaceRegion:region
mipmapLevel:mipmapLevel
slice:slice
withBytes:data
bytesPerRow:bytesPerRow
bytesPerImage:0];
bytesPerImage:bytesPer2DImage];
}
void Texture::getBytes(ContextMtl *context,
size_t bytesPerRow,
MTLRegion region,
size_t bytesPer2DInage,
const MTLRegion &region,
uint32_t mipmapLevel,
uint32_t slice,
uint8_t *dataOut)
{
ASSERT(isCPUAccessible());
@ -353,7 +403,12 @@ void Texture::getBytes(ContextMtl *context,
cmdQueue.ensureResourceReadyForCPU(this);
[get() getBytes:dataOut bytesPerRow:bytesPerRow fromRegion:region mipmapLevel:mipmapLevel];
[get() getBytes:dataOut
bytesPerRow:bytesPerRow
bytesPerImage:bytesPer2DInage
fromRegion:region
mipmapLevel:mipmapLevel
slice:slice];
}
TextureRef Texture::createCubeFaceView(uint32_t face)
@ -363,8 +418,8 @@ TextureRef Texture::createCubeFaceView(uint32_t face)
switch (textureType())
{
case MTLTextureTypeCube:
return TextureRef(
new Texture(this, MTLTextureType2D, NSMakeRange(0, mipmapLevels()), face));
return TextureRef(new Texture(
this, MTLTextureType2D, NSMakeRange(0, mipmapLevels()), NSMakeRange(face, 1)));
default:
UNREACHABLE();
return nullptr;
@ -380,8 +435,9 @@ TextureRef Texture::createSliceMipView(uint32_t slice, uint32_t level)
{
case MTLTextureTypeCube:
case MTLTextureType2D:
return TextureRef(
new Texture(this, MTLTextureType2D, NSMakeRange(level, 1), slice));
case MTLTextureType2DArray:
return TextureRef(new Texture(this, MTLTextureType2D, NSMakeRange(level, 1),
NSMakeRange(slice, 1)));
default:
UNREACHABLE();
return nullptr;
@ -389,6 +445,16 @@ TextureRef Texture::createSliceMipView(uint32_t slice, uint32_t level)
}
}
TextureRef Texture::createMipView(uint32_t level)
{
ANGLE_MTL_OBJC_SCOPE
{
NSUInteger slices = cubeFacesOrArrayLength();
return TextureRef(
new Texture(this, textureType(), NSMakeRange(level, 1), NSMakeRange(0, slices)));
}
}
TextureRef Texture::createViewWithDifferentFormat(MTLPixelFormat format)
{
ASSERT(supportFormatView());
@ -415,6 +481,20 @@ uint32_t Texture::mipmapLevels() const
return static_cast<uint32_t>(get().mipmapLevelCount);
}
uint32_t Texture::arrayLength() const
{
return static_cast<uint32_t>(get().arrayLength);
}
uint32_t Texture::cubeFacesOrArrayLength() const
{
if (textureType() == MTLTextureTypeCube)
{
return 6;
}
return arrayLength();
}
uint32_t Texture::width(uint32_t level) const
{
return static_cast<uint32_t>(GetMipSize(get().width, level));
@ -443,10 +523,14 @@ gl::Extents Texture::size(uint32_t level) const
gl::Extents Texture::size(const gl::ImageIndex &index) const
{
// Only support these texture types for now
ASSERT(!get() || textureType() == MTLTextureType2D || textureType() == MTLTextureTypeCube);
gl::Extents extents = size(index.getLevelIndex());
return size(index.getLevelIndex());
if (index.hasLayer())
{
extents.depth = 1;
}
return extents;
}
uint32_t Texture::samples() const

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

@ -183,6 +183,7 @@ void BaseRenderPassAttachmentDescToObjC(const RenderPassAttachmentDesc &src,
dst.texture = ToObjC(implicitMsTexture);
dst.level = 0;
dst.slice = 0;
dst.depthPlane = 0;
dst.resolveTexture = ToObjC(src.texture);
dst.resolveLevel = src.level;
if (dst.resolveTexture.textureType == MTLTextureType3D)
@ -210,9 +211,10 @@ void BaseRenderPassAttachmentDescToObjC(const RenderPassAttachmentDesc &src,
dst.slice = src.sliceOrDepth;
dst.depthPlane = 0;
}
dst.resolveTexture = nil;
dst.resolveLevel = 0;
dst.resolveSlice = 0;
dst.resolveTexture = nil;
dst.resolveLevel = 0;
dst.resolveSlice = 0;
dst.resolveDepthPlane = 0;
}
ANGLE_OBJC_CP_PROPERTY(dst, src, loadAction);

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

@ -41,6 +41,15 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
const gl::ImageIndex &index,
MTLColorWriteMask channelsToInit);
// Unified texture's per slice/depth texel reading function
angle::Result ReadTexturePerSliceBytes(const gl::Context *context,
const TextureRef &texture,
size_t bytesPerRow,
const gl::Rectangle &fromRegion,
uint32_t mipLevel,
uint32_t sliceOrDepth,
uint8_t *dataOut);
MTLViewport GetViewport(const gl::Rectangle &rect, double znear = 0, double zfar = 1);
MTLViewport GetViewportFlipY(const gl::Rectangle &rect,
NSUInteger screenHeight,

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

@ -64,6 +64,38 @@ uint32_t GetDeviceVendorIdFromIOKit(id<MTLDevice> device)
}
#endif
void GetSliceAndDepth(const gl::ImageIndex &index, GLint *layer, GLint *startDepth)
{
*layer = *startDepth = 0;
if (!index.hasLayer())
{
return;
}
switch (index.getType())
{
case gl::TextureType::CubeMap:
*layer = index.cubeMapFaceIndex();
break;
case gl::TextureType::_2DArray:
*layer = index.getLayerIndex();
break;
case gl::TextureType::_3D:
*startDepth = index.getLayerIndex();
break;
default:
UNREACHABLE();
break;
}
}
GLint GetSliceOrDepth(const gl::ImageIndex &index)
{
GLint layer, startDepth;
GetSliceAndDepth(index, &layer, &startDepth);
return std::max(layer, startDepth);
}
}
angle::Result InitializeTextureContents(const gl::Context *context,
@ -72,8 +104,6 @@ angle::Result InitializeTextureContents(const gl::Context *context,
const gl::ImageIndex &index)
{
ASSERT(texture && texture->valid());
ASSERT(texture->textureType() == MTLTextureType2D ||
texture->textureType() == MTLTextureTypeCube);
ContextMtl *contextMtl = mtl::GetImpl(context);
const gl::InternalFormat &intendedInternalFormat = textureObjFormat.intendedInternalFormat();
@ -88,11 +118,13 @@ angle::Result InitializeTextureContents(const gl::Context *context,
gl::Extents size = texture->size(index);
// Initialize the content to black
// Intiialize the content to black
GLint layer, startDepth;
GetSliceAndDepth(index, &layer, &startDepth);
if (texture->isCPUAccessible() && index.getType() != gl::TextureType::_2DMultisample &&
index.getType() != gl::TextureType::_2DMultisampleArray)
{
const angle::Format &dstFormat = angle::Format::Get(textureObjFormat.actualFormatId);
const size_t dstRowPitch = dstFormat.pixelBytes * size.width;
angle::MemoryBuffer conversionRow;
@ -121,14 +153,17 @@ angle::Result InitializeTextureContents(const gl::Context *context,
auto mtlRowRegion = MTLRegionMake2D(0, 0, size.width, 1);
for (NSUInteger r = 0; r < static_cast<NSUInteger>(size.height); ++r)
for (NSUInteger d = 0; d < static_cast<NSUInteger>(size.depth); ++d)
{
mtlRowRegion.origin.y = r;
mtlRowRegion.origin.z = d + startDepth;
for (NSUInteger r = 0; r < static_cast<NSUInteger>(size.height); ++r)
{
mtlRowRegion.origin.y = r;
// Upload to texture
texture->replaceRegion(contextMtl, mtlRowRegion, index.getLevelIndex(),
index.hasLayer() ? index.cubeMapFaceIndex() : 0,
conversionRow.data(), dstRowPitch);
// Upload to texture
texture->replace2DRegion(contextMtl, mtlRowRegion, index.getLevelIndex(), layer,
conversionRow.data(), dstRowPitch);
}
}
}
else
@ -147,12 +182,11 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
MTLColorWriteMask channelsToInit)
{
ContextMtl *contextMtl = mtl::GetImpl(context);
// NOTE(hqle): Support layered textures
ASSERT(!index.hasLayer());
GLint sliceOrDepth = GetSliceOrDepth(index);
// Use clear render command
RenderTargetMtl tempRtt;
tempRtt.set(texture, index.getLevelIndex(), 0, textureObjFormat);
tempRtt.set(texture, index.getLevelIndex(), sliceOrDepth, textureObjFormat);
// temporarily enable color channels requested via channelsToInit. Some emulated format has some
// channels write mask disabled when the texture is created.
@ -189,6 +223,39 @@ angle::Result InitializeTextureContentsGPU(const gl::Context *context,
return angle::Result::Continue;
}
angle::Result ReadTexturePerSliceBytes(const gl::Context *context,
const TextureRef &texture,
size_t bytesPerRow,
const gl::Rectangle &fromRegion,
uint32_t mipLevel,
uint32_t sliceOrDepth,
uint8_t *dataOut)
{
ASSERT(texture && texture->valid());
ContextMtl *contextMtl = mtl::GetImpl(context);
GLint layer = 0;
GLint startDepth = 0;
switch (texture->textureType())
{
case MTLTextureTypeCube:
case MTLTextureType2DArray:
layer = sliceOrDepth;
break;
case MTLTextureType3D:
startDepth = sliceOrDepth;
break;
default:
break;
}
MTLRegion mtlRegion = MTLRegionMake3D(fromRegion.x, fromRegion.y, startDepth, fromRegion.width,
fromRegion.height, 1);
texture->getBytes(contextMtl, bytesPerRow, 0, mtlRegion, mipLevel, layer, dataOut);
return angle::Result::Continue;
}
MTLViewport GetViewport(const gl::Rectangle &rect, double znear, double zfar)
{
MTLViewport re;

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

@ -506,6 +506,65 @@ TEST_P(CopyTexImageTest, DeleteAfterCopyingToTextures)
// Crashes on Intel GPUs on macOS.
texture2.reset();
}
// Test if glCopyTexImage2D() implementation performs conversions well from GL_TEXTURE_3D to
// GL_TEXTURE_2D.
// This is similar to CopyTexImageTestES3.CopyTexSubImageFromTexture3D but for GL_OES_texture_3D
// extension.
TEST_P(CopyTexImageTest, CopyTexSubImageFrom3DTexureOES)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_3D"));
// TODO(anglebug.com/3801)
// Seems to fail on D3D11 Windows.
ANGLE_SKIP_TEST_IF(IsD3D11() & IsWindows());
// http://anglebug.com/4927
ANGLE_SKIP_TEST_IF(IsPixel2() || IsOpenGLES());
constexpr GLsizei kDepth = 6;
// The framebuffer will be a slice of a 3d texture with a different colors for each slice. Each
// glCopyTexSubImage2D will take one face of this image to copy over a pixel in a 1x6
// framebuffer.
GLColor fboPixels[kDepth] = {GLColor::red, GLColor::yellow, GLColor::green,
GLColor::cyan, GLColor::blue, GLColor::magenta};
GLColor whitePixels[kDepth] = {GLColor::white, GLColor::white, GLColor::white,
GLColor::white, GLColor::white, GLColor::white};
GLTexture fboTex;
glBindTexture(GL_TEXTURE_3D, fboTex);
glTexImage3DOES(GL_TEXTURE_3D, 0, GL_RGBA, 1, 1, kDepth, 0, GL_RGBA, GL_UNSIGNED_BYTE,
fboPixels);
GLTexture dstTex;
glBindTexture(GL_TEXTURE_2D, dstTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, kDepth, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, whitePixels);
GLFramebuffer fbo;
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
for (GLsizei slice = 0; slice < kDepth; ++slice)
{
glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, fboTex, 0,
slice);
ASSERT_GL_NO_ERROR();
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
// Copy the fbo (a 3d slice) into a pixel of the destination texture.
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, slice, 0, 0, 0, 1, 1);
}
// Make sure all the copies are done correctly.
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dstTex, 0);
ASSERT_GL_NO_ERROR();
ASSERT_GLENUM_EQ(GL_FRAMEBUFFER_COMPLETE, glCheckFramebufferStatus(GL_FRAMEBUFFER));
for (GLsizei slice = 0; slice < kDepth; ++slice)
{
EXPECT_PIXEL_COLOR_EQ(slice, 0, fboPixels[slice]);
}
}
// specialization of CopyTexImageTest is added so that some tests can be explicitly run with an ES3
// context

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

@ -206,6 +206,15 @@ class DrawBuffersTest : public ANGLETest
verifyAttachment2DColor(index, texture, target, level, getColorForIndex(index));
}
void verifyAttachment3DOES(unsigned int index, GLuint texture, GLint level, GLint layer)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_3D"));
glFramebufferTexture3DOES(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture,
level, layer);
EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, getColorForIndex(index));
}
void verifyAttachmentLayer(unsigned int index, GLuint texture, GLint level, GLint layer)
{
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture, level, layer);
@ -597,6 +606,53 @@ TEST_P(DrawBuffersTest, BroadcastGLFragColor)
glDeleteProgram(program);
}
// Test that binding multiple layers of a 3D texture works correctly.
// This is the same as DrawBuffersTestES3.3DTextures but is used for GL_OES_texture_3D extension
// on GLES 2.0 instead.
TEST_P(DrawBuffersTest, 3DTexturesOES)
{
ANGLE_SKIP_TEST_IF(!setupTest());
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_3D"));
GLTexture texture;
glBindTexture(GL_TEXTURE_3D, texture.get());
glTexImage3DOES(GL_TEXTURE_3D, 0, GL_RGBA, getWindowWidth(), getWindowHeight(),
getWindowWidth(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_3D, texture.get(), 0,
0);
glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_3D, texture.get(), 0,
1);
glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_3D, texture.get(), 0,
2);
glFramebufferTexture3DOES(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_3D, texture.get(), 0,
3);
bool flags[8] = {true, true, true, true, false};
GLuint program;
setupMRTProgram(flags, &program);
const GLenum bufs[] = {
GL_COLOR_ATTACHMENT0,
GL_COLOR_ATTACHMENT1,
GL_COLOR_ATTACHMENT2,
GL_COLOR_ATTACHMENT3,
};
setDrawBuffers(4, bufs);
drawQuad(program, positionAttrib(), 0.5);
verifyAttachment3DOES(0, texture.get(), 0, 0);
verifyAttachment3DOES(1, texture.get(), 0, 1);
verifyAttachment3DOES(2, texture.get(), 0, 2);
verifyAttachment3DOES(3, texture.get(), 0, 3);
EXPECT_GL_NO_ERROR();
glDeleteProgram(program);
}
class DrawBuffersTestES3 : public DrawBuffersTest
{};

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

@ -58,6 +58,7 @@ class MipmapTest : public BaseMipmapTest
mCubeProgram(0),
mTexture2D(0),
mTextureCube(0),
m3DProgram(0),
mLevelZeroBlueInitData(),
mLevelZeroWhiteInitData(),
mLevelOneGreenInitData(),
@ -123,12 +124,62 @@ void main()
ASSERT_NE(0u, mCubeProgram);
}
void setUp3DProgram()
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_3D"));
// http://anglebug.com/4927
ANGLE_SKIP_TEST_IF(IsPixel2() || IsOpenGLES());
// Vertex Shader source
constexpr char kVS[] = R"(attribute vec4 position;
varying vec2 vTexCoord;
void main()
{
gl_Position = position;
vTexCoord = (position.xy * 0.5) + 0.5;
})";
constexpr char kFS[] = R"(#version 100
#extension GL_OES_texture_3D : enable
precision highp float;
uniform highp sampler3D tex;
uniform float slice;
uniform float lod;
varying vec2 vTexCoord;
void main()
{
gl_FragColor = texture3DLod(tex, vec3(vTexCoord, slice), lod);
})";
m3DProgram = CompileProgram(kVS, kFS);
if (m3DProgram == 0)
{
FAIL() << "shader compilation failed.";
}
mTexture3DSliceUniformLocation = glGetUniformLocation(m3DProgram, "slice");
ASSERT_NE(-1, mTexture3DSliceUniformLocation);
mTexture3DLODUniformLocation = glGetUniformLocation(m3DProgram, "lod");
ASSERT_NE(-1, mTexture3DLODUniformLocation);
glUseProgram(m3DProgram);
glUniform1f(mTexture3DLODUniformLocation, 0);
glUseProgram(0);
ASSERT_GL_NO_ERROR();
}
void testSetUp() override
{
setUp2DProgram();
setUpCubeProgram();
setUp3DProgram();
mLevelZeroBlueInitData =
createRGBInitData(getWindowWidth(), getWindowHeight(), 0, 0, 255); // Blue
mLevelZeroWhiteInitData =
@ -168,6 +219,7 @@ void main()
{
glDeleteProgram(m2DProgram);
glDeleteProgram(mCubeProgram);
glDeleteProgram(m3DProgram);
glDeleteFramebuffers(1, &mOffscreenFramebuffer);
glDeleteTextures(1, &mTexture2D);
glDeleteTextures(1, &mTextureCube);
@ -207,6 +259,10 @@ void main()
GLuint mTexture2D;
GLuint mTextureCube;
GLuint m3DProgram = 0;
GLint mTexture3DSliceUniformLocation;
GLint mTexture3DLODUniformLocation;
std::vector<GLubyte> mLevelZeroBlueInitData;
std::vector<GLubyte> mLevelZeroWhiteInitData;
std::vector<GLubyte> mLevelOneGreenInitData;
@ -1055,6 +1111,99 @@ TEST_P(MipmapTest, TextureCubeRenderToLevelZero)
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red);
}
// Creates a mipmapped 3D texture with two layers, and calls ANGLE's GenerateMipmap.
// Then tests if the mipmaps are rendered correctly for all two layers.
// This is the same as MipmapTestES3.MipmapsForTexture3D but for GL_OES_texture_3D extension on
// GLES 2.0 instead.
TEST_P(MipmapTest, MipmapsForTexture3DOES)
{
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_texture_3D"));
// http://anglebug.com/4927
ANGLE_SKIP_TEST_IF(IsPixel2() || IsOpenGLES());
int px = getWindowWidth() / 2;
int py = getWindowHeight() / 2;
GLTexture texture;
glBindTexture(GL_TEXTURE_3D, texture);
glTexImage3DOES(GL_TEXTURE_3D, 0, GL_RGBA, 16, 16, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage3DOES(GL_TEXTURE_3D, 1, GL_RGBA, 8, 8, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage3DOES(GL_TEXTURE_3D, 2, GL_RGBA, 4, 4, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage3DOES(GL_TEXTURE_3D, 3, GL_RGBA, 2, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glTexImage3DOES(GL_TEXTURE_3D, 4, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
// Fill the first layer with red
std::vector<GLColor> pixelsRed(16 * 16, GLColor::red);
glTexSubImage3DOES(GL_TEXTURE_3D, 0, 0, 0, 0, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
pixelsRed.data());
// Fill the second layer with green
std::vector<GLColor> pixelsGreen(16 * 16, GLColor::green);
glTexSubImage3DOES(GL_TEXTURE_3D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
pixelsGreen.data());
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
EXPECT_GL_NO_ERROR();
glGenerateMipmap(GL_TEXTURE_3D);
EXPECT_GL_NO_ERROR();
glUseProgram(m3DProgram);
EXPECT_GL_NO_ERROR();
// Mipmap level 0
// Draw the first slice
glUniform1f(mTexture3DLODUniformLocation, 0.);
glUniform1f(mTexture3DSliceUniformLocation, 0.25f);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
// Draw the second slice
glUniform1f(mTexture3DSliceUniformLocation, 0.75f);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::green);
// Regenerate mipmap of same color texture
glTexSubImage3DOES(GL_TEXTURE_3D, 0, 0, 0, 1, 16, 16, 1, GL_RGBA, GL_UNSIGNED_BYTE,
pixelsRed.data());
glGenerateMipmap(GL_TEXTURE_3D);
EXPECT_GL_NO_ERROR();
// Mipmap level 1 8*8*1
glUniform1f(mTexture3DLODUniformLocation, 1.);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
// Mipmap level 2 4*4*1
glUniform1f(mTexture3DLODUniformLocation, 2.);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
// Mipmap level 3 2*2*1
glUniform1f(mTexture3DLODUniformLocation, 3.);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
// Mipmap level 4 1*1*1
glUniform1f(mTexture3DLODUniformLocation, 4.);
drawQuad(m3DProgram, "position", 0.5f);
EXPECT_GL_NO_ERROR();
EXPECT_PIXEL_COLOR_EQ(px, py, GLColor::red);
}
// Creates a mipmapped 2D array texture with three layers, and calls ANGLE's GenerateMipmap.
// Then tests if the mipmaps are rendered correctly for all three layers.
TEST_P(MipmapTestES3, MipmapsForTextureArray)

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

@ -1074,10 +1074,87 @@ class TextureSizeTextureArrayTest : public TexCoordDrawTest
GLint mTexture1Location;
};
class Texture3DTestES3 : public TexCoordDrawTest
// Test for GL_OES_texture_3D extension
class Texture3DTestES2 : public TexCoordDrawTest
{
protected:
Texture3DTestES3() : TexCoordDrawTest(), mTexture3D(0), mTexture3DUniformLocation(-1) {}
Texture3DTestES2() : TexCoordDrawTest(), mTexture3D(0), mTexture3DUniformLocation(-1) {}
const char *getVertexShaderSource() override
{
return "#version 100\n"
"varying vec2 texcoord;\n"
"attribute vec4 position;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position.xy, 0.0, 1.0);\n"
" texcoord = (position.xy * 0.5) + 0.5;\n"
"}\n";
}
const char *getFragmentShaderSource() override
{
if (!hasTexture3DExt())
{
return "#version 100\n"
"precision highp float;\n"
"varying vec2 texcoord;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);\n"
"}\n";
}
return "#version 100\n"
"#extension GL_OES_texture_3D : enable\n"
"precision highp float;\n"
"uniform highp sampler3D tex3D;\n"
"uniform highp float level;\n"
"varying vec2 texcoord;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture3DLod(tex3D, vec3(texcoord, 0.0), level);\n"
"}\n";
}
void testSetUp() override
{
TexCoordDrawTest::testSetUp();
glGenTextures(1, &mTexture3D);
setUpProgram();
mTexture3DUniformLocation = glGetUniformLocation(mProgram, "tex3D");
if (hasTexture3DExt())
{
ASSERT_NE(-1, mTexture3DUniformLocation);
}
}
void testTearDown() override
{
glDeleteTextures(1, &mTexture3D);
TexCoordDrawTest::testTearDown();
}
bool hasTexture3DExt() const
{
// http://anglebug.com/4927
if (IsPixel2() || IsOpenGLES())
{
return false;
}
return IsGLExtensionEnabled("GL_OES_texture_3D");
}
GLuint mTexture3D;
GLint mTexture3DUniformLocation;
};
class Texture3DTestES3 : public Texture3DTestES2
{
protected:
Texture3DTestES3() : Texture3DTestES2() {}
const char *getVertexShaderSource() override
{
@ -1103,27 +1180,6 @@ class Texture3DTestES3 : public TexCoordDrawTest
" fragColor = texture(tex3D, vec3(texcoord, 0.0));\n"
"}\n";
}
void testSetUp() override
{
TexCoordDrawTest::testSetUp();
glGenTextures(1, &mTexture3D);
setUpProgram();
mTexture3DUniformLocation = glGetUniformLocation(mProgram, "tex3D");
ASSERT_NE(-1, mTexture3DUniformLocation);
}
void testTearDown() override
{
glDeleteTextures(1, &mTexture3D);
TexCoordDrawTest::testTearDown();
}
GLuint mTexture3D;
GLint mTexture3DUniformLocation;
};
class ShadowSamplerPlusSampler3DTestES3 : public TexCoordDrawTest
@ -2422,6 +2478,146 @@ TEST_P(Texture2DTest, NPOTSubImageParameters)
EXPECT_GL_NO_ERROR();
}
// Test that drawing works correctly RGBA 3D texture
TEST_P(Texture3DTestES2, RGBA)
{
ANGLE_SKIP_TEST_IF(!hasTexture3DExt());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, mTexture3D);
std::vector<GLColor> texDataGreen(2u * 2u * 2u, GLColor::green);
std::vector<GLColor> texDataRed(1u * 1u * 1u, GLColor::red);
glTexImage3DOES(GL_TEXTURE_3D, 0, GL_RGBA, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataGreen.data());
glTexImage3DOES(GL_TEXTURE_3D, 1, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataRed.data());
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
}
// Test that drawing works correctly Luminance 3D texture
TEST_P(Texture3DTestES2, Luminance)
{
ANGLE_SKIP_TEST_IF(!hasTexture3DExt());
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, mTexture3D);
std::vector<GLubyte> texData(2u * 2u * 2u, 125);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage3DOES(GL_TEXTURE_3D, 0, GL_LUMINANCE, 2, 2, 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
texData.data());
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
EXPECT_GL_NO_ERROR();
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor(125, 125, 125, 255));
}
// Test that drawing works correctly with glCopyTexSubImage3D
TEST_P(Texture3DTestES2, CopySubImageRGBA)
{
ANGLE_SKIP_TEST_IF(!hasTexture3DExt());
glClearColor(0, 0, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, mTexture3D);
std::vector<GLColor> texDataRed(4u * 4u * 4u, GLColor::red);
glTexImage3DOES(GL_TEXTURE_3D, 0, GL_RGBA, 4, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataRed.data());
glTexImage3DOES(GL_TEXTURE_3D, 1, GL_RGBA, 2, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataRed.data());
glTexImage3DOES(GL_TEXTURE_3D, 2, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
texDataRed.data());
glCopyTexSubImage3DOES(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
glCopyTexSubImage3DOES(GL_TEXTURE_3D, 1, 0, 0, 1, 0, 0, 2, 2);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
EXPECT_GL_NO_ERROR();
glClearColor(0, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
glUseProgram(mProgram);
glUniform1f(glGetUniformLocation(mProgram, "level"), 1);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::blue);
}
TEST_P(Texture3DTestES2, CopySubImageLuminance)
{
ANGLE_SKIP_TEST_IF(!hasTexture3DExt());
glClearColor(1, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, mTexture3D);
glTexImage3DOES(GL_TEXTURE_3D, 0, GL_LUMINANCE, 4, 4, 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
nullptr);
glTexImage3DOES(GL_TEXTURE_3D, 1, GL_LUMINANCE, 2, 2, 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
nullptr);
glTexImage3DOES(GL_TEXTURE_3D, 2, GL_LUMINANCE, 1, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE,
nullptr);
glCopyTexSubImage3DOES(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
glCopyTexSubImage3DOES(GL_TEXTURE_3D, 1, 0, 0, 1, 0, 0, 2, 2);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
EXPECT_GL_NO_ERROR();
glClearColor(0, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
glUseProgram(mProgram);
glUniform1f(glGetUniformLocation(mProgram, "level"), 1);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::white);
}
TEST_P(Texture3DTestES2, CopySubImageAlpha)
{
ANGLE_SKIP_TEST_IF(!hasTexture3DExt());
glClearColor(1, 0, 0, 0.5);
glClear(GL_COLOR_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_3D, mTexture3D);
glTexImage3DOES(GL_TEXTURE_3D, 0, GL_ALPHA, 4, 4, 4, 0, GL_ALPHA, GL_UNSIGNED_BYTE, nullptr);
glTexImage3DOES(GL_TEXTURE_3D, 1, GL_ALPHA, 2, 2, 2, 0, GL_ALPHA, GL_UNSIGNED_BYTE, nullptr);
glTexImage3DOES(GL_TEXTURE_3D, 2, GL_ALPHA, 1, 1, 1, 0, GL_ALPHA, GL_UNSIGNED_BYTE, nullptr);
glCopyTexSubImage3DOES(GL_TEXTURE_3D, 1, 0, 0, 0, 0, 0, 2, 2);
glCopyTexSubImage3DOES(GL_TEXTURE_3D, 1, 0, 0, 1, 0, 0, 2, 2);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
EXPECT_GL_NO_ERROR();
glClearColor(0, 1, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
glUseProgram(mProgram);
glUniform1f(glGetUniformLocation(mProgram, "level"), 1);
drawQuad(mProgram, "position", 0.5f);
EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0, 0, 0, 128), 1.0);
}
// Regression test for http://crbug.com/949985 to make sure dirty bits are propagated up from
// TextureImpl and the texture is synced before being used in a draw call.
TEST_P(Texture2DTestES3, TextureImplPropogatesDirtyBits)
@ -7340,6 +7536,7 @@ ANGLE_INSTANTIATE_TEST_ES2(SamplerArrayAsFunctionParameterTest);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DTestES3);
ANGLE_INSTANTIATE_TEST_ES31(Texture2DTestES31PPO);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DBaseMaxTestES3);
ANGLE_INSTANTIATE_TEST_ES2(Texture3DTestES2);
ANGLE_INSTANTIATE_TEST_ES3(Texture3DTestES3);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DIntegerAlpha1TestES3);
ANGLE_INSTANTIATE_TEST_ES3(Texture2DUnsignedIntegerAlpha1TestES3);