• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1//
2// Copyright 2019 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6// mtl_format_utils.mm:
7//      Implements Format conversion utilities classes that convert from angle formats
8//      to respective MTLPixelFormat and MTLVertexFormat.
9//
10
11#include "libANGLE/renderer/metal/mtl_format_utils.h"
12
13#include "common/debug.h"
14#include "libANGLE/renderer/Format.h"
15#include "libANGLE/renderer/load_functions_table.h"
16#include "libANGLE/renderer/metal/DisplayMtl.h"
17
18namespace rx
19{
20namespace mtl
21{
22
23namespace priv
24{
25
26template <typename T>
27inline T *OffsetDataPointer(uint8_t *data, size_t y, size_t z, size_t rowPitch, size_t depthPitch)
28{
29    return reinterpret_cast<T *>(data + (y * rowPitch) + (z * depthPitch));
30}
31
32template <typename T>
33inline const T *OffsetDataPointer(const uint8_t *data,
34                                  size_t y,
35                                  size_t z,
36                                  size_t rowPitch,
37                                  size_t depthPitch)
38{
39    return reinterpret_cast<const T *>(data + (y * rowPitch) + (z * depthPitch));
40}
41
42}  // namespace priv
43
44namespace
45{
46
47bool OverrideTextureCaps(const DisplayMtl *display, angle::FormatID formatId, gl::TextureCaps *caps)
48{
49    // NOTE(hqle): Auto generate this.
50    switch (formatId)
51    {
52        // NOTE: even though iOS devices don't support filtering depth textures, we still report as
53        // supported here in order for the OES_depth_texture extension to be enabled.
54        // During draw call, the filter modes will be converted to nearest.
55        case angle::FormatID::D16_UNORM:
56        case angle::FormatID::D24_UNORM_S8_UINT:
57        case angle::FormatID::D32_FLOAT_S8X24_UINT:
58        case angle::FormatID::D32_FLOAT:
59        case angle::FormatID::D32_UNORM:
60            caps->texturable = caps->filterable = caps->textureAttachment = caps->renderbuffer =
61                true;
62            return true;
63        default:
64            // NOTE(hqle): Handle more cases
65            return false;
66    }
67}
68
69void GenerateTextureCapsMap(const FormatTable &formatTable,
70                            const DisplayMtl *display,
71                            gl::TextureCapsMap *capsMapOut,
72                            uint32_t *maxSamplesOut)
73{
74    auto &textureCapsMap = *capsMapOut;
75    auto formatVerifier  = [&](const gl::InternalFormat &internalFormatInfo) {
76        angle::FormatID angleFormatId =
77            angle::Format::InternalFormatToID(internalFormatInfo.sizedInternalFormat);
78        const Format &mtlFormat = formatTable.getPixelFormat(angleFormatId);
79        if (!mtlFormat.valid())
80        {
81            return;
82        }
83        const FormatCaps &formatCaps = mtlFormat.getCaps();
84
85        gl::TextureCaps textureCaps;
86
87        // First let check whether we can override certain special cases.
88        if (!OverrideTextureCaps(display, mtlFormat.intendedFormatId, &textureCaps))
89        {
90            // Fill the texture caps using pixel format's caps
91            textureCaps.filterable = mtlFormat.getCaps().filterable;
92            textureCaps.renderbuffer =
93                mtlFormat.getCaps().colorRenderable || mtlFormat.getCaps().depthRenderable;
94            textureCaps.texturable        = true;
95            textureCaps.textureAttachment = textureCaps.renderbuffer;
96            textureCaps.blendable         = mtlFormat.getCaps().blendable;
97        }
98
99        if (formatCaps.multisample)
100        {
101            constexpr uint32_t sampleCounts[] = {2, 4, 8};
102            for (auto sampleCount : sampleCounts)
103            {
104                if ([display->getMetalDevice() supportsTextureSampleCount:sampleCount])
105                {
106                    textureCaps.sampleCounts.insert(sampleCount);
107                    *maxSamplesOut = std::max(*maxSamplesOut, sampleCount);
108                }
109            }
110        }
111
112        textureCapsMap.set(mtlFormat.intendedFormatId, textureCaps);
113    };
114
115    // Texture caps map.
116    const gl::FormatSet &internalFormats = gl::GetAllSizedInternalFormats();
117    for (const auto internalFormat : internalFormats)
118    {
119        const gl::InternalFormat &internalFormatInfo =
120            gl::GetSizedInternalFormatInfo(internalFormat);
121
122        formatVerifier(internalFormatInfo);
123    }
124}
125
126}  // namespace
127
128// FormatBase implementation
129const angle::Format &FormatBase::actualAngleFormat() const
130{
131    return angle::Format::Get(actualFormatId);
132}
133
134const angle::Format &FormatBase::intendedAngleFormat() const
135{
136    return angle::Format::Get(intendedFormatId);
137}
138
139// Format implementation
140const gl::InternalFormat &Format::intendedInternalFormat() const
141{
142    return gl::GetSizedInternalFormatInfo(intendedAngleFormat().glInternalFormat);
143}
144
145const gl::InternalFormat &Format::actualInternalFormat() const
146{
147    return gl::GetSizedInternalFormatInfo(actualAngleFormat().glInternalFormat);
148}
149
150bool Format::needConversion(angle::FormatID srcFormatId) const
151{
152    if ((srcFormatId == angle::FormatID::BC1_RGB_UNORM_BLOCK &&
153         actualFormatId == angle::FormatID::BC1_RGBA_UNORM_BLOCK) ||
154        (srcFormatId == angle::FormatID::BC1_RGB_UNORM_SRGB_BLOCK &&
155         actualFormatId == angle::FormatID::BC1_RGBA_UNORM_SRGB_BLOCK))
156    {
157        // When texture swizzling is available, DXT1 RGB format will be swizzled with RGB1.
158        // WebGL allows unswizzled mapping when swizzling is not available. No need to convert.
159        return false;
160    }
161    return srcFormatId != actualFormatId;
162}
163
164bool Format::isPVRTC() const
165{
166    switch (metalFormat)
167    {
168#if (TARGET_OS_IOS && !TARGET_OS_MACCATALYST) || \
169    (TARGET_OS_OSX && (__MAC_OS_X_VERSION_MAX_ALLOWED >= 110000))
170        case MTLPixelFormatPVRTC_RGB_2BPP:
171        case MTLPixelFormatPVRTC_RGB_2BPP_sRGB:
172        case MTLPixelFormatPVRTC_RGB_4BPP:
173        case MTLPixelFormatPVRTC_RGB_4BPP_sRGB:
174        case MTLPixelFormatPVRTC_RGBA_2BPP:
175        case MTLPixelFormatPVRTC_RGBA_2BPP_sRGB:
176        case MTLPixelFormatPVRTC_RGBA_4BPP:
177        case MTLPixelFormatPVRTC_RGBA_4BPP_sRGB:
178            return true;
179#endif
180        default:
181            return false;
182    }
183}
184
185// FormatTable implementation
186angle::Result FormatTable::initialize(const DisplayMtl *display)
187{
188    mMaxSamples = 0;
189
190    // Initialize native format caps
191    initNativeFormatCaps(display);
192
193    for (size_t i = 0; i < angle::kNumANGLEFormats; ++i)
194    {
195        const auto formatId = static_cast<angle::FormatID>(i);
196
197        mPixelFormatTable[i].init(display, formatId);
198        mPixelFormatTable[i].caps = mNativePixelFormatCapsTable[mPixelFormatTable[i].metalFormat];
199
200        if (mPixelFormatTable[i].actualFormatId != mPixelFormatTable[i].intendedFormatId)
201        {
202            mPixelFormatTable[i].textureLoadFunctions = angle::GetLoadFunctionsMap(
203                mPixelFormatTable[i].intendedAngleFormat().glInternalFormat,
204                mPixelFormatTable[i].actualFormatId);
205        }
206
207        mVertexFormatTables[0][i].init(formatId, false);
208        mVertexFormatTables[1][i].init(formatId, true);
209    }
210
211    // TODO(anglebug.com/5505): unmerged change from WebKit was here -
212    // D24S8 fallback to D32_FLOAT_S8X24_UINT, since removed.
213
214    return angle::Result::Continue;
215}
216
217void FormatTable::generateTextureCaps(const DisplayMtl *display, gl::TextureCapsMap *capsMapOut)
218{
219    GenerateTextureCapsMap(*this, display, capsMapOut, &mMaxSamples);
220}
221
222const Format &FormatTable::getPixelFormat(angle::FormatID angleFormatId) const
223{
224    return mPixelFormatTable[static_cast<size_t>(angleFormatId)];
225}
226const FormatCaps &FormatTable::getNativeFormatCaps(MTLPixelFormat mtlFormat) const
227{
228    ASSERT(mNativePixelFormatCapsTable.count(mtlFormat));
229    return mNativePixelFormatCapsTable.at(mtlFormat);
230}
231const VertexFormat &FormatTable::getVertexFormat(angle::FormatID angleFormatId,
232                                                 bool tightlyPacked) const
233{
234    auto tableIdx = tightlyPacked ? 1 : 0;
235    return mVertexFormatTables[tableIdx][static_cast<size_t>(angleFormatId)];
236}
237
238void FormatTable::setFormatCaps(MTLPixelFormat formatId,
239                                bool filterable,
240                                bool writable,
241                                bool blendable,
242                                bool multisample,
243                                bool resolve,
244                                bool colorRenderable)
245{
246    setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable,
247                  false, 0);
248}
249void FormatTable::setFormatCaps(MTLPixelFormat formatId,
250                                bool filterable,
251                                bool writable,
252                                bool blendable,
253                                bool multisample,
254                                bool resolve,
255                                bool colorRenderable,
256                                NSUInteger pixelBytes,
257                                NSUInteger channels)
258{
259    setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable,
260                  false, pixelBytes, channels);
261}
262
263void FormatTable::setFormatCaps(MTLPixelFormat formatId,
264                                bool filterable,
265                                bool writable,
266                                bool blendable,
267                                bool multisample,
268                                bool resolve,
269                                bool colorRenderable,
270                                bool depthRenderable)
271{
272    setFormatCaps(formatId, filterable, writable, blendable, multisample, resolve, colorRenderable,
273                  depthRenderable, 0, 0);
274}
275void FormatTable::setFormatCaps(MTLPixelFormat id,
276                                bool filterable,
277                                bool writable,
278                                bool blendable,
279                                bool multisample,
280                                bool resolve,
281                                bool colorRenderable,
282                                bool depthRenderable,
283                                NSUInteger pixelBytes,
284                                NSUInteger channels)
285{
286    mNativePixelFormatCapsTable[id].filterable      = filterable;
287    mNativePixelFormatCapsTable[id].writable        = writable;
288    mNativePixelFormatCapsTable[id].colorRenderable = colorRenderable;
289    mNativePixelFormatCapsTable[id].depthRenderable = depthRenderable;
290    mNativePixelFormatCapsTable[id].blendable       = blendable;
291    mNativePixelFormatCapsTable[id].multisample     = multisample;
292    mNativePixelFormatCapsTable[id].resolve         = resolve;
293    mNativePixelFormatCapsTable[id].pixelBytes      = pixelBytes;
294    mNativePixelFormatCapsTable[id].pixelBytesMSAA  = pixelBytes;
295    mNativePixelFormatCapsTable[id].channels        = channels;
296    if (channels != 0)
297        mNativePixelFormatCapsTable[id].alignment = MAX(pixelBytes / channels, 1U);
298}
299
300void FormatTable::setCompressedFormatCaps(MTLPixelFormat formatId, bool filterable)
301{
302    setFormatCaps(formatId, filterable, false, false, false, false, false, false);
303}
304
305void FormatTable::adjustFormatCapsForDevice(const mtl::ContextDevice &device,
306                                            MTLPixelFormat id,
307                                            bool supportsiOS2,
308                                            bool supportsiOS4)
309{
310#if !(TARGET_OS_OSX || TARGET_OS_MACCATALYST)
311
312    NSUInteger pixelBytesRender     = mNativePixelFormatCapsTable[id].pixelBytes;
313    NSUInteger pixelBytesRenderMSAA = mNativePixelFormatCapsTable[id].pixelBytesMSAA;
314    NSUInteger alignment            = mNativePixelFormatCapsTable[id].alignment;
315
316// Override the current pixelBytesRender
317#    define SPECIFIC(_pixelFormat, _pixelBytesRender)                                            \
318        case _pixelFormat:                                                                       \
319            pixelBytesRender     = _pixelBytesRender;                                            \
320            pixelBytesRenderMSAA = _pixelBytesRender;                                            \
321            alignment =                                                                          \
322                supportsiOS4 ? _pixelBytesRender / mNativePixelFormatCapsTable[id].channels : 4; \
323            break
324// Override the current pixel bytes render, and MSAA
325#    define SPECIFIC_MSAA(_pixelFormat, _pixelBytesRender, _pixelBytesRenderMSAA)                \
326        case _pixelFormat:                                                                       \
327            pixelBytesRender     = _pixelBytesRender;                                            \
328            pixelBytesRenderMSAA = _pixelBytesRenderMSAA;                                        \
329            alignment =                                                                          \
330                supportsiOS4 ? _pixelBytesRender / mNativePixelFormatCapsTable[id].channels : 4; \
331            break
332// Override the current pixelBytesRender, and alignment
333#    define SPECIFIC_ALIGN(_pixelFormat, _pixelBytesRender, _alignment) \
334        case _pixelFormat:                                              \
335            pixelBytesRender     = _pixelBytesRender;                   \
336            pixelBytesRenderMSAA = _pixelBytesRender;                   \
337            alignment            = _alignment;                          \
338            break
339
340    if (!mNativePixelFormatCapsTable[id].compressed)
341    {
342        // On AppleGPUFamily4+, there is no 4byte minimum requirement for render targets
343        uint32_t minSize     = supportsiOS4 ? 1U : 4U;
344        pixelBytesRender     = MAX(mNativePixelFormatCapsTable[id].pixelBytes, minSize);
345        pixelBytesRenderMSAA = pixelBytesRender;
346        alignment =
347            supportsiOS4 ? MAX(pixelBytesRender / mNativePixelFormatCapsTable[id].channels, 1U) : 4;
348    }
349
350    // This list of tables starts from a general multi-platform table,
351    // to specific platforms (i.e. ios2, ios4) inheriting from the previous tables
352
353    // Start off with the general case
354    switch ((NSUInteger)id)
355    {
356        SPECIFIC(MTLPixelFormatB5G6R5Unorm, 4U);
357        SPECIFIC(MTLPixelFormatA1BGR5Unorm, 4U);
358        SPECIFIC(MTLPixelFormatABGR4Unorm, 4U);
359        SPECIFIC(MTLPixelFormatBGR5A1Unorm, 4U);
360
361        SPECIFIC(MTLPixelFormatRGBA8Unorm, 4U);
362        SPECIFIC(MTLPixelFormatBGRA8Unorm, 4U);
363
364        SPECIFIC_MSAA(MTLPixelFormatRGBA8Unorm_sRGB, 4U, 8U);
365        SPECIFIC_MSAA(MTLPixelFormatBGRA8Unorm_sRGB, 4U, 8U);
366        SPECIFIC_MSAA(MTLPixelFormatRGBA8Snorm, 4U, 8U);
367        SPECIFIC_MSAA(MTLPixelFormatRGB10A2Uint, 4U, 8U);
368
369        SPECIFIC(MTLPixelFormatRGB10A2Unorm, 8U);
370        SPECIFIC(MTLPixelFormatBGR10A2Unorm, 8U);
371
372        SPECIFIC(MTLPixelFormatRG11B10Float, 8U);
373
374        SPECIFIC(MTLPixelFormatRGB9E5Float, 8U);
375
376        SPECIFIC(MTLPixelFormatStencil8, 1U);
377    }
378
379    // Override based ios2
380    if (supportsiOS2)
381    {
382        switch ((NSUInteger)id)
383        {
384            SPECIFIC(MTLPixelFormatB5G6R5Unorm, 8U);
385            SPECIFIC(MTLPixelFormatA1BGR5Unorm, 8U);
386            SPECIFIC(MTLPixelFormatABGR4Unorm, 8U);
387            SPECIFIC(MTLPixelFormatBGR5A1Unorm, 8U);
388            SPECIFIC_MSAA(MTLPixelFormatRGBA8Unorm, 4U, 8U);
389            SPECIFIC_MSAA(MTLPixelFormatBGRA8Unorm, 4U, 8U);
390        }
391    }
392
393    // Override based on ios4
394    if (supportsiOS4)
395    {
396        switch ((NSUInteger)id)
397        {
398            SPECIFIC_ALIGN(MTLPixelFormatB5G6R5Unorm, 6U, 2U);
399            SPECIFIC(MTLPixelFormatRGBA8Unorm, 4U);
400            SPECIFIC(MTLPixelFormatBGRA8Unorm, 4U);
401
402            SPECIFIC(MTLPixelFormatRGBA8Unorm_sRGB, 4U);
403            SPECIFIC(MTLPixelFormatBGRA8Unorm_sRGB, 4U);
404
405            SPECIFIC(MTLPixelFormatRGBA8Snorm, 4U);
406
407            SPECIFIC_ALIGN(MTLPixelFormatRGB10A2Unorm, 4U, 4U);
408            SPECIFIC_ALIGN(MTLPixelFormatBGR10A2Unorm, 4U, 4U);
409            SPECIFIC(MTLPixelFormatRGB10A2Uint, 8U);
410
411            SPECIFIC_ALIGN(MTLPixelFormatRG11B10Float, 4U, 4U);
412
413            SPECIFIC_ALIGN(MTLPixelFormatRGB9E5Float, 4U, 4U);
414        }
415    }
416    mNativePixelFormatCapsTable[id].pixelBytes     = pixelBytesRender;
417    mNativePixelFormatCapsTable[id].pixelBytesMSAA = pixelBytesRenderMSAA;
418    mNativePixelFormatCapsTable[id].alignment      = alignment;
419
420#    undef SPECIFIC
421#    undef SPECIFIC_ALIGN
422#    undef SPECIFIC_MSAA
423#endif
424    // macOS does not need to perform any additoinal adjustment. These values are only used to check
425    // valid MRT sizes on iOS.
426}
427
428void FormatTable::initNativeFormatCaps(const DisplayMtl *display)
429{
430    initNativeFormatCapsAutogen(display);
431}
432
433}  // namespace mtl
434}  // namespace rx
435