зеркало из https://github.com/AvaloniaUI/angle.git
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:
Родитель
f2196ad676
Коммит
acda9ddea1
|
@ -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 ©Texture(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 ®ion,
|
||||
uint32_t mipmapLevel,
|
||||
uint32_t slice,
|
||||
const uint8_t *data,
|
||||
size_t bytesPerRow);
|
||||
|
||||
void replaceRegion(ContextMtl *context,
|
||||
MTLRegion region,
|
||||
const MTLRegion ®ion,
|
||||
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 ®ion,
|
||||
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 ®ion,
|
||||
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 ®ion,
|
||||
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 ®ion,
|
||||
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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче