blob: 1130cae6e5c545efa597b413d90a49275430e69f [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.
//
// mtl_format_utils.h:
// Declares Format conversion utilities classes that convert from angle formats
// to respective MTLPixelFormat and MTLVertexFormat.
//
#ifndef LIBANGLE_RENDERER_METAL_MTL_FORMAT_UTILS_H_
#define LIBANGLE_RENDERER_METAL_MTL_FORMAT_UTILS_H_
#import <Metal/Metal.h>
#include <unordered_map>
#include "common/angleutils.h"
#include "libANGLE/Caps.h"
#include "libANGLE/formatutils.h"
#include "libANGLE/renderer/copyvertex.h"
#include "libANGLE/renderer/renderer_utils.h"
namespace rx
{
class DisplayMtl;
namespace mtl
{
class ContextDevice;
LoadFunctionMap GetLoadFunctionsMap(GLenum internalFormat, angle::FormatID angleFormat);
struct FormatBase
{
inline bool operator==(const FormatBase &rhs) const
{
return intendedFormatId == rhs.intendedFormatId && actualFormatId == rhs.actualFormatId;
}
inline bool operator!=(const FormatBase &rhs) const { return !((*this) == rhs); }
const angle::Format &actualAngleFormat() const;
const angle::Format &intendedAngleFormat() const;
angle::FormatID actualFormatId = angle::FormatID::NONE;
angle::FormatID intendedFormatId = angle::FormatID::NONE;
};
struct FormatCaps
{
bool isRenderable() const { return colorRenderable || depthRenderable; }
bool filterable = false;
bool writable = false;
bool colorRenderable = false;
bool depthRenderable = false;
bool blendable = false;
bool multisample = false; // can be used as MSAA target
bool resolve = false; // Can be used as resolve target
bool compressed = false;
NSUInteger pixelBytes = 0;
NSUInteger pixelBytesMSAA = 0;
NSUInteger channels = 0;
uint8_t alignment = 0;
};
// Pixel format
struct Format : public FormatBase
{
Format() = default;
static angle::FormatID MetalToAngleFormatID(MTLPixelFormat formatMtl);
const gl::InternalFormat &intendedInternalFormat() const;
const gl::InternalFormat &actualInternalFormat() const;
bool valid() const { return metalFormat != MTLPixelFormatInvalid; }
bool hasDepthAndStencilBits() const
{
return actualAngleFormat().depthBits && actualAngleFormat().stencilBits;
}
bool hasDepthOrStencilBits() const
{
return actualAngleFormat().depthBits || actualAngleFormat().stencilBits;
}
bool isPVRTC() const;
const FormatCaps &getCaps() const { return *caps; }
// Need conversion between source format and this format?
bool needConversion(angle::FormatID srcFormatId) const;
MTLPixelFormat metalFormat = MTLPixelFormatInvalid;
LoadFunctionMap textureLoadFunctions = nullptr;
InitializeTextureDataFunction initFunction = nullptr;
const FormatCaps *caps = nullptr;
bool swizzled = false;
std::array<GLenum, 4> swizzle;
private:
void init(const DisplayMtl *display, angle::FormatID intendedFormatId);
friend class FormatTable;
};
// Vertex format
struct VertexFormat : public FormatBase
{
VertexFormat() = default;
MTLVertexFormat metalFormat = MTLVertexFormatInvalid;
VertexCopyFunction vertexLoadFunction = nullptr;
uint32_t defaultAlpha = 0;
// Intended and actual format have same GL type, and possibly only differ in number of
// components?
bool actualSameGLType = true;
private:
void init(angle::FormatID angleFormatId, bool tightlyPacked = false);
friend class FormatTable;
};
class FormatTable final : angle::NonCopyable
{
public:
FormatTable() = default;
~FormatTable() = default;
angle::Result initialize(const DisplayMtl *display);
void generateTextureCaps(const DisplayMtl *display,
gl::TextureCapsMap *capsMapOut,
std::vector<GLenum> *compressedFormatsOut);
const Format &getPixelFormat(angle::FormatID angleFormatId) const;
const FormatCaps &getNativeFormatCaps(MTLPixelFormat mtlFormat) const;
// tightlyPacked means this format will be used in a tightly packed vertex buffer.
// In that case, it's easier to just convert everything to float to ensure
// Metal alignment requirements between 2 elements inside the buffer will be met regardless
// of how many components each element has.
const VertexFormat &getVertexFormat(angle::FormatID angleFormatId, bool tightlyPacked) const;
uint32_t getMaxSamples() const { return mMaxSamples; }
private:
void initNativeFormatCapsAutogen(const DisplayMtl *display);
void initNativeFormatCaps(const DisplayMtl *display);
void setFormatCaps(MTLPixelFormat formatId,
bool filterable,
bool writable,
bool blendable,
bool multisample,
bool resolve,
bool colorRenderable);
void setFormatCaps(MTLPixelFormat formatId,
bool filterable,
bool writable,
bool blendable,
bool multisample,
bool resolve,
bool colorRenderable,
NSUInteger bytesPerChannel,
NSUInteger channels);
void setFormatCaps(MTLPixelFormat formatId,
bool filterable,
bool writable,
bool blendable,
bool multisample,
bool resolve,
bool colorRenderable,
bool depthRenderable);
void setFormatCaps(MTLPixelFormat formatId,
bool filterable,
bool writable,
bool blendable,
bool multisample,
bool resolve,
bool colorRenderable,
bool depthRenderable,
NSUInteger bytesPerChannel,
NSUInteger channels);
void setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable);
void adjustFormatCapsForDevice(const mtl::ContextDevice &device,
MTLPixelFormat id,
bool supportsiOS2,
bool supportsiOS4);
std::array<Format, angle::kNumANGLEFormats> mPixelFormatTable;
angle::HashMap<MTLPixelFormat, FormatCaps> mNativePixelFormatCapsTable;
// One for tightly packed buffers, one for general cases.
std::array<VertexFormat, angle::kNumANGLEFormats> mVertexFormatTables[2];
uint32_t mMaxSamples;
};
} // namespace mtl
} // namespace rx
#endif /* LIBANGLE_RENDERER_METAL_MTL_FORMAT_UTILS_H_ */