blob: d6082c82bfdcf5d378f04fc0d3958a51a1e5a59c [file] [log] [blame]
//
// Copyright 2019 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// TextureMtl.h:
// Defines the class interface for TextureMtl, implementing TextureImpl.
//
#ifndef LIBANGLE_RENDERER_METAL_TEXTUREMTL_H_
#define LIBANGLE_RENDERER_METAL_TEXTUREMTL_H_
#include <map>
#include "common/PackedEnums.h"
#include "libANGLE/renderer/TextureImpl.h"
#include "libANGLE/renderer/metal/RenderTargetMtl.h"
#include "libANGLE/renderer/metal/SurfaceMtl.h"
#include "libANGLE/renderer/metal/mtl_command_buffer.h"
#include "libANGLE/renderer/metal/mtl_context_device.h"
#include "libANGLE/renderer/metal/mtl_resources.h"
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:
TextureMtl(const gl::TextureState &state);
// Texture view
TextureMtl(const TextureMtl &mtl, GLenum format);
~TextureMtl() override;
void onDestroy(const gl::Context *context) override;
angle::Result setImage(const gl::Context *context,
const gl::ImageIndex &index,
GLenum internalFormat,
const gl::Extents &size,
GLenum format,
GLenum type,
const gl::PixelUnpackState &unpack,
gl::Buffer *unpackBuffer,
const uint8_t *pixels) override;
angle::Result setSubImage(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Box &area,
GLenum format,
GLenum type,
const gl::PixelUnpackState &unpack,
gl::Buffer *unpackBuffer,
const uint8_t *pixels) override;
angle::Result setCompressedImage(const gl::Context *context,
const gl::ImageIndex &index,
GLenum internalFormat,
const gl::Extents &size,
const gl::PixelUnpackState &unpack,
size_t imageSize,
const uint8_t *pixels) override;
angle::Result setCompressedSubImage(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Box &area,
GLenum format,
const gl::PixelUnpackState &unpack,
size_t imageSize,
const uint8_t *pixels) override;
angle::Result copyImage(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Rectangle &sourceArea,
GLenum internalFormat,
gl::Framebuffer *source) override;
angle::Result copySubImage(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::Rectangle &sourceArea,
gl::Framebuffer *source) override;
angle::Result copyTexture(const gl::Context *context,
const gl::ImageIndex &index,
GLenum internalFormat,
GLenum type,
GLint sourceLevel,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const gl::Texture *source) override;
angle::Result copySubTexture(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
GLint sourceLevel,
const gl::Box &sourceBox,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const gl::Texture *source) override;
angle::Result copyCompressedTexture(const gl::Context *context,
const gl::Texture *source) override;
angle::Result setStorage(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size) override;
angle::Result setStorageExternalMemory(const gl::Context *context,
gl::TextureType type,
size_t levels,
GLenum internalFormat,
const gl::Extents &size,
gl::MemoryObject *memoryObject,
GLuint64 offset,
GLbitfield createFlags,
GLbitfield usageFlags,
const void *imageCreateInfoPNext) override;
angle::Result setEGLImageTarget(const gl::Context *context,
gl::TextureType type,
egl::Image *image) override;
angle::Result setImageExternal(const gl::Context *context,
gl::TextureType type,
egl::Stream *stream,
const egl::Stream::GLTextureDescription &desc) override;
angle::Result generateMipmap(const gl::Context *context) override;
angle::Result setBaseLevel(const gl::Context *context, GLuint baseLevel) override;
angle::Result bindTexImage(const gl::Context *context, egl::Surface *surface) override;
angle::Result releaseTexImage(const gl::Context *context) override;
angle::Result getAttachmentRenderTarget(const gl::Context *context,
GLenum binding,
const gl::ImageIndex &imageIndex,
GLsizei samples,
FramebufferAttachmentRenderTarget **rtOut) override;
angle::Result syncState(const gl::Context *context,
const gl::Texture::DirtyBits &dirtyBits,
gl::Command source) override;
angle::Result setStorageMultisample(const gl::Context *context,
gl::TextureType type,
GLsizei samples,
GLint internalformat,
const gl::Extents &size,
bool fixedSampleLocations) override;
angle::Result initializeContents(const gl::Context *context,
const gl::ImageIndex &imageIndex) override;
// The texture's data is initially initialized and stored in an array
// of images through glTexImage*/glCopyTex* calls. During draw calls, the caller must make sure
// the actual texture is created by calling this method to transfer the stored images data
// to the actual texture.
angle::Result ensureTextureCreated(const gl::Context *context);
angle::Result bindToShader(const gl::Context *context,
mtl::RenderCommandEncoder *cmdEncoder,
gl::ShaderType shaderType,
gl::Sampler *sampler, /** nullable */
int textureSlotIndex,
int samplerSlotIndex);
const mtl::Format &getFormat() const { return mFormat; }
const mtl::TextureRef &getNativeTexture() const { return mNativeTexture; }
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 onBaseMaxLevelsChanged(const gl::Context *context);
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,
const mtl::MipmapNativeLevel &nativeLevel);
angle::Result ensureNativeLevelViewsCreated();
angle::Result checkForEmulatedChannels(const gl::Context *context,
const mtl::Format &mtlFormat,
const mtl::TextureRef &texture);
mtl::MipmapNativeLevel 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;
mtl::TextureRef &getImplicitMSTexture(const gl::ImageIndex &imageIndex);
// If levels = 0, this function will create full mipmaps texture.
angle::Result setStorageImpl(const gl::Context *context,
gl::TextureType type,
size_t levels,
const mtl::Format &mtlFormat,
const gl::Extents &size);
angle::Result redefineImage(const gl::Context *context,
const gl::ImageIndex &index,
const mtl::Format &mtlFormat,
const gl::Extents &size);
angle::Result setImageImpl(const gl::Context *context,
const gl::ImageIndex &index,
const gl::InternalFormat &dstFormatInfo,
const gl::Extents &size,
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,
const gl::Box &area,
const gl::InternalFormat &formatInfo,
GLenum type,
const gl::PixelUnpackState &unpack,
gl::Buffer *unpackBuffer,
const uint8_t *pixels);
angle::Result copySubImageImpl(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::Rectangle &sourceArea,
const gl::InternalFormat &internalFormat,
const FramebufferMtl *source,
const RenderTargetMtl *sourceRtt);
angle::Result copySubImageWithDraw(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::Rectangle &sourceArea,
const gl::InternalFormat &internalFormat,
const FramebufferMtl *source,
const RenderTargetMtl *sourceRtt);
angle::Result copySubImageCPU(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::Rectangle &sourceArea,
const gl::InternalFormat &internalFormat,
const FramebufferMtl *source,
const RenderTargetMtl *sourceRtt);
angle::Result copySubTextureImpl(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::InternalFormat &internalFormat,
GLint sourceLevel,
const gl::Box &sourceBox,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const gl::Texture *source);
angle::Result copySubTextureWithDraw(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::InternalFormat &internalFormat,
const mtl::MipmapNativeLevel &sourceNativeLevel,
const gl::Box &sourceBox,
const angle::Format &sourceAngleFormat,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
bool unpackUnmultiplyAlpha,
const mtl::TextureRef &sourceTexture);
angle::Result copySubTextureCPU(const gl::Context *context,
const gl::ImageIndex &index,
const gl::Offset &destOffset,
const gl::InternalFormat &internalFormat,
const mtl::MipmapNativeLevel &sourceNativeLevel,
const gl::Box &sourceBox,
const angle::Format &sourceAngleFormat,
bool unpackFlipY,
bool unpackPremultiplyAlpha,
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 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);
mtl::Format mFormat;
SurfaceMtl *mBoundSurface = nil;
// The real texture used by Metal draw calls.
mtl::TextureRef mNativeTexture = nil;
id<MTLSamplerState> mMetalSamplerState = nil;
// 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.
// NOTE:
// - The second dimension is indexed by configured base level + actual native level
// - For Cube map, there will be at most 6 entries in the map 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).
// - These three variables' second dimension are indexed by image index (base level included).
std::map<int, gl::TexLevelArray<ImageDefinitionMtl>> mTexImageDefs;
std::map<int, gl::TexLevelArray<RenderTargetMtl>> mPerLayerRenderTargets;
std::map<int, gl::TexLevelArray<mtl::TextureRef>> mImplicitMSTextures;
// Mipmap views are indexed by native level (ignored base level):
mtl::NativeTexLevelArray mNativeLevelViews;
// The swizzled view used for shader sampling.
mtl::TextureRef mNativeSwizzleSamplingView;
GLuint mCurrentBaseLevel = 0;
GLuint mCurrentMaxLevel = 1000;
bool mIsPow2 = false;
};
} // namespace rx
#endif /* LIBANGLE_RENDERER_METAL_TEXTUREMTL_H_ */