xref: /aosp_15_r20/external/angle/src/tests/gl_tests/ImageTestMetal.mm (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker//
2*8975f5c5SAndroid Build Coastguard Worker// Copyright 2021 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker// Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker// found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker//
6*8975f5c5SAndroid Build Coastguard Worker// ImageTestMetal:
7*8975f5c5SAndroid Build Coastguard Worker//   Tests the correctness of eglImage with native Metal texture extensions.
8*8975f5c5SAndroid Build Coastguard Worker//
9*8975f5c5SAndroid Build Coastguard Worker
10*8975f5c5SAndroid Build Coastguard Worker#include "test_utils/ANGLETest.h"
11*8975f5c5SAndroid Build Coastguard Worker
12*8975f5c5SAndroid Build Coastguard Worker#include "common/mathutil.h"
13*8975f5c5SAndroid Build Coastguard Worker#include "test_utils/gl_raii.h"
14*8975f5c5SAndroid Build Coastguard Worker#include "util/EGLWindow.h"
15*8975f5c5SAndroid Build Coastguard Worker
16*8975f5c5SAndroid Build Coastguard Worker#include <CoreFoundation/CoreFoundation.h>
17*8975f5c5SAndroid Build Coastguard Worker#include <Metal/Metal.h>
18*8975f5c5SAndroid Build Coastguard Worker#include <gmock/gmock.h>
19*8975f5c5SAndroid Build Coastguard Worker#include <span>
20*8975f5c5SAndroid Build Coastguard Worker
21*8975f5c5SAndroid Build Coastguard Workernamespace angle
22*8975f5c5SAndroid Build Coastguard Worker{
23*8975f5c5SAndroid Build Coastguard Workernamespace
24*8975f5c5SAndroid Build Coastguard Worker{
25*8975f5c5SAndroid Build Coastguard Workerconstexpr char kOESExt[]                      = "GL_OES_EGL_image";
26*8975f5c5SAndroid Build Coastguard Workerconstexpr char kBaseExt[]                     = "EGL_KHR_image_base";
27*8975f5c5SAndroid Build Coastguard Workerconstexpr char kDeviceMtlExt[]                = "EGL_ANGLE_device_metal";
28*8975f5c5SAndroid Build Coastguard Workerconstexpr char kEGLMtlImageNativeTextureExt[] = "EGL_ANGLE_metal_texture_client_buffer";
29*8975f5c5SAndroid Build Coastguard Workerconstexpr EGLint kDefaultAttribs[]            = {
30*8975f5c5SAndroid Build Coastguard Worker    EGL_NONE,
31*8975f5c5SAndroid Build Coastguard Worker};
32*8975f5c5SAndroid Build Coastguard Worker
33*8975f5c5SAndroid Build Coastguard Workertemplate <typename T>
34*8975f5c5SAndroid Build Coastguard Workerclass ScopedMetalObjectRef : angle::NonCopyable
35*8975f5c5SAndroid Build Coastguard Worker{
36*8975f5c5SAndroid Build Coastguard Worker  public:
37*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalObjectRef() = default;
38*8975f5c5SAndroid Build Coastguard Worker
39*8975f5c5SAndroid Build Coastguard Worker    explicit ScopedMetalObjectRef(T &&surface) : mObject(surface) {}
40*8975f5c5SAndroid Build Coastguard Worker
41*8975f5c5SAndroid Build Coastguard Worker    ~ScopedMetalObjectRef()
42*8975f5c5SAndroid Build Coastguard Worker    {
43*8975f5c5SAndroid Build Coastguard Worker        if (mObject)
44*8975f5c5SAndroid Build Coastguard Worker        {
45*8975f5c5SAndroid Build Coastguard Worker            release();
46*8975f5c5SAndroid Build Coastguard Worker            mObject = nil;
47*8975f5c5SAndroid Build Coastguard Worker        }
48*8975f5c5SAndroid Build Coastguard Worker    }
49*8975f5c5SAndroid Build Coastguard Worker
50*8975f5c5SAndroid Build Coastguard Worker    T get() const { return mObject; }
51*8975f5c5SAndroid Build Coastguard Worker
52*8975f5c5SAndroid Build Coastguard Worker    operator bool() const { return !!mObject; }
53*8975f5c5SAndroid Build Coastguard Worker
54*8975f5c5SAndroid Build Coastguard Worker    // auto cast to T
55*8975f5c5SAndroid Build Coastguard Worker    operator T() const { return mObject; }
56*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalObjectRef(const ScopedMetalObjectRef &other)
57*8975f5c5SAndroid Build Coastguard Worker    {
58*8975f5c5SAndroid Build Coastguard Worker        if (mObject)
59*8975f5c5SAndroid Build Coastguard Worker        {
60*8975f5c5SAndroid Build Coastguard Worker            release();
61*8975f5c5SAndroid Build Coastguard Worker        }
62*8975f5c5SAndroid Build Coastguard Worker        mObject = other.mObject;
63*8975f5c5SAndroid Build Coastguard Worker    }
64*8975f5c5SAndroid Build Coastguard Worker
65*8975f5c5SAndroid Build Coastguard Worker    explicit ScopedMetalObjectRef(ScopedMetalObjectRef &&other)
66*8975f5c5SAndroid Build Coastguard Worker    {
67*8975f5c5SAndroid Build Coastguard Worker        if (mObject)
68*8975f5c5SAndroid Build Coastguard Worker        {
69*8975f5c5SAndroid Build Coastguard Worker            release();
70*8975f5c5SAndroid Build Coastguard Worker        }
71*8975f5c5SAndroid Build Coastguard Worker        mObject       = other.mObject;
72*8975f5c5SAndroid Build Coastguard Worker        other.mObject = nil;
73*8975f5c5SAndroid Build Coastguard Worker    }
74*8975f5c5SAndroid Build Coastguard Worker
75*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalObjectRef &operator=(ScopedMetalObjectRef &&other)
76*8975f5c5SAndroid Build Coastguard Worker    {
77*8975f5c5SAndroid Build Coastguard Worker        if (mObject)
78*8975f5c5SAndroid Build Coastguard Worker        {
79*8975f5c5SAndroid Build Coastguard Worker            release();
80*8975f5c5SAndroid Build Coastguard Worker        }
81*8975f5c5SAndroid Build Coastguard Worker        mObject       = other.mObject;
82*8975f5c5SAndroid Build Coastguard Worker        other.mObject = nil;
83*8975f5c5SAndroid Build Coastguard Worker
84*8975f5c5SAndroid Build Coastguard Worker        return *this;
85*8975f5c5SAndroid Build Coastguard Worker    }
86*8975f5c5SAndroid Build Coastguard Worker
87*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalObjectRef &operator=(const ScopedMetalObjectRef &other)
88*8975f5c5SAndroid Build Coastguard Worker    {
89*8975f5c5SAndroid Build Coastguard Worker        if (mObject)
90*8975f5c5SAndroid Build Coastguard Worker        {
91*8975f5c5SAndroid Build Coastguard Worker            release();
92*8975f5c5SAndroid Build Coastguard Worker        }
93*8975f5c5SAndroid Build Coastguard Worker        mObject = other.mObject;
94*8975f5c5SAndroid Build Coastguard Worker
95*8975f5c5SAndroid Build Coastguard Worker        return *this;
96*8975f5c5SAndroid Build Coastguard Worker    }
97*8975f5c5SAndroid Build Coastguard Worker
98*8975f5c5SAndroid Build Coastguard Worker  private:
99*8975f5c5SAndroid Build Coastguard Worker    void release()
100*8975f5c5SAndroid Build Coastguard Worker    {
101*8975f5c5SAndroid Build Coastguard Worker#if !__has_feature(objc_arc)
102*8975f5c5SAndroid Build Coastguard Worker        [mObject release];
103*8975f5c5SAndroid Build Coastguard Worker#endif
104*8975f5c5SAndroid Build Coastguard Worker    }
105*8975f5c5SAndroid Build Coastguard Worker
106*8975f5c5SAndroid Build Coastguard Worker    T mObject = nil;
107*8975f5c5SAndroid Build Coastguard Worker};
108*8975f5c5SAndroid Build Coastguard Worker
109*8975f5c5SAndroid Build Coastguard Workerusing ScopedMetalTextureRef      = ScopedMetalObjectRef<id<MTLTexture>>;
110*8975f5c5SAndroid Build Coastguard Workerusing ScopedMetalBufferRef       = ScopedMetalObjectRef<id<MTLBuffer>>;
111*8975f5c5SAndroid Build Coastguard Workerusing ScopedMetalCommandQueueRef = ScopedMetalObjectRef<id<MTLCommandQueue>>;
112*8975f5c5SAndroid Build Coastguard Worker
113*8975f5c5SAndroid Build Coastguard Worker}  // anonymous namespace
114*8975f5c5SAndroid Build Coastguard Worker
115*8975f5c5SAndroid Build Coastguard Workerbool IsDepthOrStencil(MTLPixelFormat format)
116*8975f5c5SAndroid Build Coastguard Worker{
117*8975f5c5SAndroid Build Coastguard Worker    switch (format)
118*8975f5c5SAndroid Build Coastguard Worker    {
119*8975f5c5SAndroid Build Coastguard Worker        case MTLPixelFormatDepth16Unorm:
120*8975f5c5SAndroid Build Coastguard Worker        case MTLPixelFormatDepth32Float:
121*8975f5c5SAndroid Build Coastguard Worker        case MTLPixelFormatStencil8:
122*8975f5c5SAndroid Build Coastguard Worker        case MTLPixelFormatDepth24Unorm_Stencil8:
123*8975f5c5SAndroid Build Coastguard Worker        case MTLPixelFormatDepth32Float_Stencil8:
124*8975f5c5SAndroid Build Coastguard Worker        case MTLPixelFormatX32_Stencil8:
125*8975f5c5SAndroid Build Coastguard Worker        case MTLPixelFormatX24_Stencil8:
126*8975f5c5SAndroid Build Coastguard Worker            return true;
127*8975f5c5SAndroid Build Coastguard Worker
128*8975f5c5SAndroid Build Coastguard Worker        default:
129*8975f5c5SAndroid Build Coastguard Worker            return false;
130*8975f5c5SAndroid Build Coastguard Worker    }
131*8975f5c5SAndroid Build Coastguard Worker}
132*8975f5c5SAndroid Build Coastguard Worker
133*8975f5c5SAndroid Build Coastguard WorkerScopedMetalTextureRef CreateMetalTexture2D(id<MTLDevice> deviceMtl,
134*8975f5c5SAndroid Build Coastguard Worker                                           int width,
135*8975f5c5SAndroid Build Coastguard Worker                                           int height,
136*8975f5c5SAndroid Build Coastguard Worker                                           MTLPixelFormat format,
137*8975f5c5SAndroid Build Coastguard Worker                                           int arrayLength)
138*8975f5c5SAndroid Build Coastguard Worker{
139*8975f5c5SAndroid Build Coastguard Worker    @autoreleasepool
140*8975f5c5SAndroid Build Coastguard Worker    {
141*8975f5c5SAndroid Build Coastguard Worker        MTLTextureDescriptor *desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format
142*8975f5c5SAndroid Build Coastguard Worker                                                                                        width:width
143*8975f5c5SAndroid Build Coastguard Worker                                                                                       height:width
144*8975f5c5SAndroid Build Coastguard Worker                                                                                    mipmapped:NO];
145*8975f5c5SAndroid Build Coastguard Worker        desc.usage                 = MTLTextureUsageShaderRead | MTLTextureUsageRenderTarget;
146*8975f5c5SAndroid Build Coastguard Worker        if (IsDepthOrStencil(format))
147*8975f5c5SAndroid Build Coastguard Worker        {
148*8975f5c5SAndroid Build Coastguard Worker            desc.storageMode = MTLStorageModePrivate;
149*8975f5c5SAndroid Build Coastguard Worker        }
150*8975f5c5SAndroid Build Coastguard Worker        if (arrayLength)
151*8975f5c5SAndroid Build Coastguard Worker        {
152*8975f5c5SAndroid Build Coastguard Worker            desc.arrayLength = arrayLength;
153*8975f5c5SAndroid Build Coastguard Worker            desc.textureType = MTLTextureType2DArray;
154*8975f5c5SAndroid Build Coastguard Worker        }
155*8975f5c5SAndroid Build Coastguard Worker        ScopedMetalTextureRef re([deviceMtl newTextureWithDescriptor:desc]);
156*8975f5c5SAndroid Build Coastguard Worker        return re;
157*8975f5c5SAndroid Build Coastguard Worker    }
158*8975f5c5SAndroid Build Coastguard Worker}
159*8975f5c5SAndroid Build Coastguard Worker
160*8975f5c5SAndroid Build Coastguard Workerid<MTLSharedEvent> CreateMetalSharedEvent(id<MTLDevice> deviceMtl)
161*8975f5c5SAndroid Build Coastguard Worker{
162*8975f5c5SAndroid Build Coastguard Worker    id<MTLSharedEvent> sharedEvent = [deviceMtl newSharedEvent];
163*8975f5c5SAndroid Build Coastguard Worker    sharedEvent.label              = @"TestSharedEvent";
164*8975f5c5SAndroid Build Coastguard Worker    return sharedEvent;
165*8975f5c5SAndroid Build Coastguard Worker}
166*8975f5c5SAndroid Build Coastguard Worker
167*8975f5c5SAndroid Build Coastguard WorkerEGLSync CreateEGLSyncFromMetalSharedEvent(EGLDisplay display,
168*8975f5c5SAndroid Build Coastguard Worker                                          id<MTLSharedEvent> sharedEvent,
169*8975f5c5SAndroid Build Coastguard Worker                                          uint64_t signalValue,
170*8975f5c5SAndroid Build Coastguard Worker                                          bool signaled)
171*8975f5c5SAndroid Build Coastguard Worker{
172*8975f5c5SAndroid Build Coastguard Worker    EGLAttrib signalValueHi            = signalValue >> 32;
173*8975f5c5SAndroid Build Coastguard Worker    EGLAttrib signalValueLo            = signalValue & 0xffffffff;
174*8975f5c5SAndroid Build Coastguard Worker    std::vector<EGLAttrib> syncAttribs = {
175*8975f5c5SAndroid Build Coastguard Worker        EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE,          reinterpret_cast<EGLAttrib>(sharedEvent),
176*8975f5c5SAndroid Build Coastguard Worker        EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_HI_ANGLE, signalValueHi,
177*8975f5c5SAndroid Build Coastguard Worker        EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_LO_ANGLE, signalValueLo};
178*8975f5c5SAndroid Build Coastguard Worker
179*8975f5c5SAndroid Build Coastguard Worker    if (signaled)
180*8975f5c5SAndroid Build Coastguard Worker    {
181*8975f5c5SAndroid Build Coastguard Worker        syncAttribs.push_back(EGL_SYNC_CONDITION);
182*8975f5c5SAndroid Build Coastguard Worker        syncAttribs.push_back(EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE);
183*8975f5c5SAndroid Build Coastguard Worker    }
184*8975f5c5SAndroid Build Coastguard Worker
185*8975f5c5SAndroid Build Coastguard Worker    syncAttribs.push_back(EGL_NONE);
186*8975f5c5SAndroid Build Coastguard Worker
187*8975f5c5SAndroid Build Coastguard Worker    EGLSync syncWithSharedEvent =
188*8975f5c5SAndroid Build Coastguard Worker        eglCreateSync(display, EGL_SYNC_METAL_SHARED_EVENT_ANGLE, syncAttribs.data());
189*8975f5c5SAndroid Build Coastguard Worker    EXPECT_NE(syncWithSharedEvent, EGL_NO_SYNC);
190*8975f5c5SAndroid Build Coastguard Worker
191*8975f5c5SAndroid Build Coastguard Worker    return syncWithSharedEvent;
192*8975f5c5SAndroid Build Coastguard Worker}
193*8975f5c5SAndroid Build Coastguard Worker
194*8975f5c5SAndroid Build Coastguard Workerclass ImageTestMetal : public ANGLETest<>
195*8975f5c5SAndroid Build Coastguard Worker{
196*8975f5c5SAndroid Build Coastguard Worker  protected:
197*8975f5c5SAndroid Build Coastguard Worker    ImageTestMetal()
198*8975f5c5SAndroid Build Coastguard Worker    {
199*8975f5c5SAndroid Build Coastguard Worker        setWindowWidth(128);
200*8975f5c5SAndroid Build Coastguard Worker        setWindowHeight(128);
201*8975f5c5SAndroid Build Coastguard Worker        setConfigRedBits(8);
202*8975f5c5SAndroid Build Coastguard Worker        setConfigGreenBits(8);
203*8975f5c5SAndroid Build Coastguard Worker        setConfigBlueBits(8);
204*8975f5c5SAndroid Build Coastguard Worker        setConfigAlphaBits(8);
205*8975f5c5SAndroid Build Coastguard Worker        setConfigDepthBits(24);
206*8975f5c5SAndroid Build Coastguard Worker    }
207*8975f5c5SAndroid Build Coastguard Worker
208*8975f5c5SAndroid Build Coastguard Worker    void testSetUp() override
209*8975f5c5SAndroid Build Coastguard Worker    {
210*8975f5c5SAndroid Build Coastguard Worker        constexpr char kVS[] = "precision highp float;\n"
211*8975f5c5SAndroid Build Coastguard Worker                               "attribute vec4 position;\n"
212*8975f5c5SAndroid Build Coastguard Worker                               "varying vec2 texcoord;\n"
213*8975f5c5SAndroid Build Coastguard Worker                               "\n"
214*8975f5c5SAndroid Build Coastguard Worker                               "void main()\n"
215*8975f5c5SAndroid Build Coastguard Worker                               "{\n"
216*8975f5c5SAndroid Build Coastguard Worker                               "    gl_Position = position;\n"
217*8975f5c5SAndroid Build Coastguard Worker                               "    texcoord = (position.xy * 0.5) + 0.5;\n"
218*8975f5c5SAndroid Build Coastguard Worker                               "    texcoord.y = 1.0 - texcoord.y;\n"
219*8975f5c5SAndroid Build Coastguard Worker                               "}\n";
220*8975f5c5SAndroid Build Coastguard Worker
221*8975f5c5SAndroid Build Coastguard Worker        constexpr char kTextureFS[] = "precision highp float;\n"
222*8975f5c5SAndroid Build Coastguard Worker                                      "uniform sampler2D tex;\n"
223*8975f5c5SAndroid Build Coastguard Worker                                      "varying vec2 texcoord;\n"
224*8975f5c5SAndroid Build Coastguard Worker                                      "\n"
225*8975f5c5SAndroid Build Coastguard Worker                                      "void main()\n"
226*8975f5c5SAndroid Build Coastguard Worker                                      "{\n"
227*8975f5c5SAndroid Build Coastguard Worker                                      "    gl_FragColor = texture2D(tex, texcoord);\n"
228*8975f5c5SAndroid Build Coastguard Worker                                      "}\n";
229*8975f5c5SAndroid Build Coastguard Worker
230*8975f5c5SAndroid Build Coastguard Worker        mTextureProgram = CompileProgram(kVS, kTextureFS);
231*8975f5c5SAndroid Build Coastguard Worker        if (mTextureProgram == 0)
232*8975f5c5SAndroid Build Coastguard Worker        {
233*8975f5c5SAndroid Build Coastguard Worker            FAIL() << "shader compilation failed.";
234*8975f5c5SAndroid Build Coastguard Worker        }
235*8975f5c5SAndroid Build Coastguard Worker
236*8975f5c5SAndroid Build Coastguard Worker        mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex");
237*8975f5c5SAndroid Build Coastguard Worker
238*8975f5c5SAndroid Build Coastguard Worker        ASSERT_GL_NO_ERROR();
239*8975f5c5SAndroid Build Coastguard Worker    }
240*8975f5c5SAndroid Build Coastguard Worker
241*8975f5c5SAndroid Build Coastguard Worker    void testTearDown() override { glDeleteProgram(mTextureProgram); }
242*8975f5c5SAndroid Build Coastguard Worker
243*8975f5c5SAndroid Build Coastguard Worker    id<MTLDevice> getMtlDevice()
244*8975f5c5SAndroid Build Coastguard Worker    {
245*8975f5c5SAndroid Build Coastguard Worker        EGLAttrib angleDevice = 0;
246*8975f5c5SAndroid Build Coastguard Worker        EGLAttrib device      = 0;
247*8975f5c5SAndroid Build Coastguard Worker        EXPECT_EGL_TRUE(
248*8975f5c5SAndroid Build Coastguard Worker            eglQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice));
249*8975f5c5SAndroid Build Coastguard Worker
250*8975f5c5SAndroid Build Coastguard Worker        EXPECT_EGL_TRUE(eglQueryDeviceAttribEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice),
251*8975f5c5SAndroid Build Coastguard Worker                                                EGL_METAL_DEVICE_ANGLE, &device));
252*8975f5c5SAndroid Build Coastguard Worker
253*8975f5c5SAndroid Build Coastguard Worker        return (__bridge id<MTLDevice>)reinterpret_cast<void *>(device);
254*8975f5c5SAndroid Build Coastguard Worker    }
255*8975f5c5SAndroid Build Coastguard Worker
256*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef createMtlTexture2D(int width, int height, MTLPixelFormat format)
257*8975f5c5SAndroid Build Coastguard Worker    {
258*8975f5c5SAndroid Build Coastguard Worker        id<MTLDevice> device = getMtlDevice();
259*8975f5c5SAndroid Build Coastguard Worker
260*8975f5c5SAndroid Build Coastguard Worker        return CreateMetalTexture2D(device, width, height, format, 0);
261*8975f5c5SAndroid Build Coastguard Worker    }
262*8975f5c5SAndroid Build Coastguard Worker
263*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef createMtlTexture2DArray(int width,
264*8975f5c5SAndroid Build Coastguard Worker                                                  int height,
265*8975f5c5SAndroid Build Coastguard Worker                                                  int arrayLength,
266*8975f5c5SAndroid Build Coastguard Worker                                                  MTLPixelFormat format)
267*8975f5c5SAndroid Build Coastguard Worker    {
268*8975f5c5SAndroid Build Coastguard Worker        id<MTLDevice> device = getMtlDevice();
269*8975f5c5SAndroid Build Coastguard Worker
270*8975f5c5SAndroid Build Coastguard Worker        return CreateMetalTexture2D(device, width, height, format, arrayLength);
271*8975f5c5SAndroid Build Coastguard Worker    }
272*8975f5c5SAndroid Build Coastguard Worker
273*8975f5c5SAndroid Build Coastguard Worker    void getTextureSliceBytes(id<MTLTexture> texture,
274*8975f5c5SAndroid Build Coastguard Worker                              unsigned bytesPerRow,
275*8975f5c5SAndroid Build Coastguard Worker                              MTLRegion region,
276*8975f5c5SAndroid Build Coastguard Worker                              unsigned mipmapLevel,
277*8975f5c5SAndroid Build Coastguard Worker                              unsigned slice,
278*8975f5c5SAndroid Build Coastguard Worker                              std::span<uint8_t> sliceImage)
279*8975f5c5SAndroid Build Coastguard Worker    {
280*8975f5c5SAndroid Build Coastguard Worker        @autoreleasepool
281*8975f5c5SAndroid Build Coastguard Worker        {
282*8975f5c5SAndroid Build Coastguard Worker            id<MTLDevice> device = texture.device;
283*8975f5c5SAndroid Build Coastguard Worker            ScopedMetalBufferRef readBuffer([device
284*8975f5c5SAndroid Build Coastguard Worker                newBufferWithLength:sliceImage.size()
285*8975f5c5SAndroid Build Coastguard Worker                            options:MTLResourceStorageModeShared]);
286*8975f5c5SAndroid Build Coastguard Worker            ScopedMetalCommandQueueRef commandQueue([device newCommandQueue]);
287*8975f5c5SAndroid Build Coastguard Worker            id<MTLCommandBuffer> commandBuffer    = [commandQueue commandBuffer];
288*8975f5c5SAndroid Build Coastguard Worker            id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
289*8975f5c5SAndroid Build Coastguard Worker            [blitEncoder copyFromTexture:texture
290*8975f5c5SAndroid Build Coastguard Worker                             sourceSlice:slice
291*8975f5c5SAndroid Build Coastguard Worker                             sourceLevel:mipmapLevel
292*8975f5c5SAndroid Build Coastguard Worker                            sourceOrigin:region.origin
293*8975f5c5SAndroid Build Coastguard Worker                              sourceSize:region.size
294*8975f5c5SAndroid Build Coastguard Worker                                toBuffer:readBuffer
295*8975f5c5SAndroid Build Coastguard Worker                       destinationOffset:0
296*8975f5c5SAndroid Build Coastguard Worker                  destinationBytesPerRow:bytesPerRow
297*8975f5c5SAndroid Build Coastguard Worker                destinationBytesPerImage:sliceImage.size()];
298*8975f5c5SAndroid Build Coastguard Worker            [blitEncoder endEncoding];
299*8975f5c5SAndroid Build Coastguard Worker            [commandBuffer commit];
300*8975f5c5SAndroid Build Coastguard Worker            [commandBuffer waitUntilCompleted];
301*8975f5c5SAndroid Build Coastguard Worker            memcpy(sliceImage.data(), readBuffer.get().contents, sliceImage.size());
302*8975f5c5SAndroid Build Coastguard Worker        }
303*8975f5c5SAndroid Build Coastguard Worker    }
304*8975f5c5SAndroid Build Coastguard Worker    void sourceMetalTarget2D_helper(GLubyte data[4],
305*8975f5c5SAndroid Build Coastguard Worker                                    const EGLint *attribs,
306*8975f5c5SAndroid Build Coastguard Worker                                    EGLImageKHR *imageOut,
307*8975f5c5SAndroid Build Coastguard Worker                                    GLuint *textureOut);
308*8975f5c5SAndroid Build Coastguard Worker
309*8975f5c5SAndroid Build Coastguard Worker    void verifyResultsTexture(GLuint texture,
310*8975f5c5SAndroid Build Coastguard Worker                              const GLubyte data[4],
311*8975f5c5SAndroid Build Coastguard Worker                              GLenum textureTarget,
312*8975f5c5SAndroid Build Coastguard Worker                              GLuint program,
313*8975f5c5SAndroid Build Coastguard Worker                              GLuint textureUniform)
314*8975f5c5SAndroid Build Coastguard Worker    {
315*8975f5c5SAndroid Build Coastguard Worker        // Draw a quad with the target texture
316*8975f5c5SAndroid Build Coastguard Worker        glUseProgram(program);
317*8975f5c5SAndroid Build Coastguard Worker        glBindTexture(textureTarget, texture);
318*8975f5c5SAndroid Build Coastguard Worker        glUniform1i(textureUniform, 0);
319*8975f5c5SAndroid Build Coastguard Worker
320*8975f5c5SAndroid Build Coastguard Worker        drawQuad(program, "position", 0.5f);
321*8975f5c5SAndroid Build Coastguard Worker
322*8975f5c5SAndroid Build Coastguard Worker        // Expect that the rendered quad has the same color as the source texture
323*8975f5c5SAndroid Build Coastguard Worker        EXPECT_PIXEL_NEAR(0, 0, data[0], data[1], data[2], data[3], 1.0);
324*8975f5c5SAndroid Build Coastguard Worker    }
325*8975f5c5SAndroid Build Coastguard Worker
326*8975f5c5SAndroid Build Coastguard Worker    void verifyResults2D(GLuint texture, const GLubyte data[4])
327*8975f5c5SAndroid Build Coastguard Worker    {
328*8975f5c5SAndroid Build Coastguard Worker        verifyResultsTexture(texture, data, GL_TEXTURE_2D, mTextureProgram,
329*8975f5c5SAndroid Build Coastguard Worker                             mTextureUniformLocation);
330*8975f5c5SAndroid Build Coastguard Worker    }
331*8975f5c5SAndroid Build Coastguard Worker
332*8975f5c5SAndroid Build Coastguard Worker    void drawColorQuad(GLColor color)
333*8975f5c5SAndroid Build Coastguard Worker    {
334*8975f5c5SAndroid Build Coastguard Worker        ANGLE_GL_PROGRAM(program, essl1_shaders::vs::Simple(), essl1_shaders::fs::UniformColor());
335*8975f5c5SAndroid Build Coastguard Worker        glUseProgram(program);
336*8975f5c5SAndroid Build Coastguard Worker        GLint colorUniformLocation =
337*8975f5c5SAndroid Build Coastguard Worker            glGetUniformLocation(program, angle::essl1_shaders::ColorUniform());
338*8975f5c5SAndroid Build Coastguard Worker        ASSERT_NE(colorUniformLocation, -1);
339*8975f5c5SAndroid Build Coastguard Worker        glUniform4fv(colorUniformLocation, 1, color.toNormalizedVector().data());
340*8975f5c5SAndroid Build Coastguard Worker        drawQuad(program, essl1_shaders::PositionAttrib(), 0);
341*8975f5c5SAndroid Build Coastguard Worker        glUseProgram(0);
342*8975f5c5SAndroid Build Coastguard Worker    }
343*8975f5c5SAndroid Build Coastguard Worker
344*8975f5c5SAndroid Build Coastguard Worker    bool hasDepth24Stencil8PixelFormat()
345*8975f5c5SAndroid Build Coastguard Worker    {
346*8975f5c5SAndroid Build Coastguard Worker        id<MTLDevice> device = getMtlDevice();
347*8975f5c5SAndroid Build Coastguard Worker        return device.depth24Stencil8PixelFormatSupported;
348*8975f5c5SAndroid Build Coastguard Worker    }
349*8975f5c5SAndroid Build Coastguard Worker
350*8975f5c5SAndroid Build Coastguard Worker    bool hasImageNativeMetalTextureExt() const
351*8975f5c5SAndroid Build Coastguard Worker    {
352*8975f5c5SAndroid Build Coastguard Worker        if (!IsMetal())
353*8975f5c5SAndroid Build Coastguard Worker        {
354*8975f5c5SAndroid Build Coastguard Worker            return false;
355*8975f5c5SAndroid Build Coastguard Worker        }
356*8975f5c5SAndroid Build Coastguard Worker        EGLAttrib angleDevice = 0;
357*8975f5c5SAndroid Build Coastguard Worker        eglQueryDisplayAttribEXT(getEGLWindow()->getDisplay(), EGL_DEVICE_EXT, &angleDevice);
358*8975f5c5SAndroid Build Coastguard Worker        if (!angleDevice)
359*8975f5c5SAndroid Build Coastguard Worker        {
360*8975f5c5SAndroid Build Coastguard Worker            return false;
361*8975f5c5SAndroid Build Coastguard Worker        }
362*8975f5c5SAndroid Build Coastguard Worker        auto extensionString = static_cast<const char *>(
363*8975f5c5SAndroid Build Coastguard Worker            eglQueryDeviceStringEXT(reinterpret_cast<EGLDeviceEXT>(angleDevice), EGL_EXTENSIONS));
364*8975f5c5SAndroid Build Coastguard Worker        if (strstr(extensionString, kDeviceMtlExt) == nullptr)
365*8975f5c5SAndroid Build Coastguard Worker        {
366*8975f5c5SAndroid Build Coastguard Worker            return false;
367*8975f5c5SAndroid Build Coastguard Worker        }
368*8975f5c5SAndroid Build Coastguard Worker        return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(),
369*8975f5c5SAndroid Build Coastguard Worker                                            kEGLMtlImageNativeTextureExt);
370*8975f5c5SAndroid Build Coastguard Worker    }
371*8975f5c5SAndroid Build Coastguard Worker
372*8975f5c5SAndroid Build Coastguard Worker    bool hasOESExt() const { return IsGLExtensionEnabled(kOESExt); }
373*8975f5c5SAndroid Build Coastguard Worker
374*8975f5c5SAndroid Build Coastguard Worker    bool hasBaseExt() const
375*8975f5c5SAndroid Build Coastguard Worker    {
376*8975f5c5SAndroid Build Coastguard Worker        return IsEGLDisplayExtensionEnabled(getEGLWindow()->getDisplay(), kBaseExt);
377*8975f5c5SAndroid Build Coastguard Worker    }
378*8975f5c5SAndroid Build Coastguard Worker
379*8975f5c5SAndroid Build Coastguard Worker    GLuint mTextureProgram;
380*8975f5c5SAndroid Build Coastguard Worker    GLint mTextureUniformLocation;
381*8975f5c5SAndroid Build Coastguard Worker};
382*8975f5c5SAndroid Build Coastguard Worker
383*8975f5c5SAndroid Build Coastguard Workervoid ImageTestMetal::sourceMetalTarget2D_helper(GLubyte data[4],
384*8975f5c5SAndroid Build Coastguard Worker                                                const EGLint *attribs,
385*8975f5c5SAndroid Build Coastguard Worker                                                EGLImageKHR *imageOut,
386*8975f5c5SAndroid Build Coastguard Worker                                                GLuint *textureOut)
387*8975f5c5SAndroid Build Coastguard Worker{
388*8975f5c5SAndroid Build Coastguard Worker    EGLWindow *window = getEGLWindow();
389*8975f5c5SAndroid Build Coastguard Worker
390*8975f5c5SAndroid Build Coastguard Worker    // Create MTLTexture
391*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef textureMtl = createMtlTexture2D(1, 1, MTLPixelFormatRGBA8Unorm);
392*8975f5c5SAndroid Build Coastguard Worker
393*8975f5c5SAndroid Build Coastguard Worker    // Create image
394*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image =
395*8975f5c5SAndroid Build Coastguard Worker        eglCreateImageKHR(window->getDisplay(), EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
396*8975f5c5SAndroid Build Coastguard Worker                          reinterpret_cast<EGLClientBuffer>(textureMtl.get()), attribs);
397*8975f5c5SAndroid Build Coastguard Worker    ASSERT_EGL_SUCCESS();
398*8975f5c5SAndroid Build Coastguard Worker
399*8975f5c5SAndroid Build Coastguard Worker    // Write the data to the MTLTexture
400*8975f5c5SAndroid Build Coastguard Worker    [textureMtl replaceRegion:MTLRegionMake2D(0, 0, 1, 1)
401*8975f5c5SAndroid Build Coastguard Worker                  mipmapLevel:0
402*8975f5c5SAndroid Build Coastguard Worker                        slice:0
403*8975f5c5SAndroid Build Coastguard Worker                    withBytes:data
404*8975f5c5SAndroid Build Coastguard Worker                  bytesPerRow:4
405*8975f5c5SAndroid Build Coastguard Worker                bytesPerImage:0];
406*8975f5c5SAndroid Build Coastguard Worker
407*8975f5c5SAndroid Build Coastguard Worker    // Create a texture target to bind the egl image
408*8975f5c5SAndroid Build Coastguard Worker    GLuint target;
409*8975f5c5SAndroid Build Coastguard Worker    glGenTextures(1, &target);
410*8975f5c5SAndroid Build Coastguard Worker    glBindTexture(GL_TEXTURE_2D, target);
411*8975f5c5SAndroid Build Coastguard Worker    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
412*8975f5c5SAndroid Build Coastguard Worker
413*8975f5c5SAndroid Build Coastguard Worker    *imageOut   = image;
414*8975f5c5SAndroid Build Coastguard Worker    *textureOut = target;
415*8975f5c5SAndroid Build Coastguard Worker}
416*8975f5c5SAndroid Build Coastguard Worker
417*8975f5c5SAndroid Build Coastguard Worker// Testing source metal EGL image, target 2D texture
418*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, SourceMetalTarget2D)
419*8975f5c5SAndroid Build Coastguard Worker{
420*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
421*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
422*8975f5c5SAndroid Build Coastguard Worker
423*8975f5c5SAndroid Build Coastguard Worker    EGLWindow *window = getEGLWindow();
424*8975f5c5SAndroid Build Coastguard Worker
425*8975f5c5SAndroid Build Coastguard Worker    // Create the Image
426*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image;
427*8975f5c5SAndroid Build Coastguard Worker    GLuint texTarget;
428*8975f5c5SAndroid Build Coastguard Worker    GLubyte data[4] = {7, 51, 197, 231};
429*8975f5c5SAndroid Build Coastguard Worker    sourceMetalTarget2D_helper(data, kDefaultAttribs, &image, &texTarget);
430*8975f5c5SAndroid Build Coastguard Worker
431*8975f5c5SAndroid Build Coastguard Worker    // Use texture target bound to egl image as source and render to framebuffer
432*8975f5c5SAndroid Build Coastguard Worker    // Verify that data in framebuffer matches that in the egl image
433*8975f5c5SAndroid Build Coastguard Worker    verifyResults2D(texTarget, data);
434*8975f5c5SAndroid Build Coastguard Worker
435*8975f5c5SAndroid Build Coastguard Worker    // Clean up
436*8975f5c5SAndroid Build Coastguard Worker    eglDestroyImageKHR(window->getDisplay(), image);
437*8975f5c5SAndroid Build Coastguard Worker    glDeleteTextures(1, &texTarget);
438*8975f5c5SAndroid Build Coastguard Worker}
439*8975f5c5SAndroid Build Coastguard Worker
440*8975f5c5SAndroid Build Coastguard Worker// Create source metal EGL image, target 2D texture, then trigger texture respecification.
441*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, SourceMetal2DTargetTextureRespecifySize)
442*8975f5c5SAndroid Build Coastguard Worker{
443*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
444*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
445*8975f5c5SAndroid Build Coastguard Worker
446*8975f5c5SAndroid Build Coastguard Worker    EGLWindow *window = getEGLWindow();
447*8975f5c5SAndroid Build Coastguard Worker
448*8975f5c5SAndroid Build Coastguard Worker    // Create the Image
449*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image;
450*8975f5c5SAndroid Build Coastguard Worker    GLuint texTarget;
451*8975f5c5SAndroid Build Coastguard Worker    GLubyte data[4] = {7, 51, 197, 231};
452*8975f5c5SAndroid Build Coastguard Worker    sourceMetalTarget2D_helper(data, kDefaultAttribs, &image, &texTarget);
453*8975f5c5SAndroid Build Coastguard Worker
454*8975f5c5SAndroid Build Coastguard Worker    // Use texture target bound to egl image as source and render to framebuffer
455*8975f5c5SAndroid Build Coastguard Worker    // Verify that data in framebuffer matches that in the egl image
456*8975f5c5SAndroid Build Coastguard Worker    verifyResults2D(texTarget, data);
457*8975f5c5SAndroid Build Coastguard Worker
458*8975f5c5SAndroid Build Coastguard Worker    // Respecify texture size and verify results
459*8975f5c5SAndroid Build Coastguard Worker    std::array<GLubyte, 16> referenceColor;
460*8975f5c5SAndroid Build Coastguard Worker    referenceColor.fill(127);
461*8975f5c5SAndroid Build Coastguard Worker    glBindTexture(GL_TEXTURE_2D, texTarget);
462*8975f5c5SAndroid Build Coastguard Worker    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
463*8975f5c5SAndroid Build Coastguard Worker                 referenceColor.data());
464*8975f5c5SAndroid Build Coastguard Worker    glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
465*8975f5c5SAndroid Build Coastguard Worker                 referenceColor.data());
466*8975f5c5SAndroid Build Coastguard Worker    ASSERT_GL_NO_ERROR();
467*8975f5c5SAndroid Build Coastguard Worker
468*8975f5c5SAndroid Build Coastguard Worker    // Expect that the target texture has the reference color values
469*8975f5c5SAndroid Build Coastguard Worker    verifyResults2D(texTarget, referenceColor.data());
470*8975f5c5SAndroid Build Coastguard Worker
471*8975f5c5SAndroid Build Coastguard Worker    // Clean up
472*8975f5c5SAndroid Build Coastguard Worker    eglDestroyImageKHR(window->getDisplay(), image);
473*8975f5c5SAndroid Build Coastguard Worker    glDeleteTextures(1, &texTarget);
474*8975f5c5SAndroid Build Coastguard Worker}
475*8975f5c5SAndroid Build Coastguard Worker
476*8975f5c5SAndroid Build Coastguard Worker// Tests that OpenGL can sample from a texture bound with Metal texture slice.
477*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, SourceMetalTarget2DArray)
478*8975f5c5SAndroid Build Coastguard Worker{
479*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
480*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
481*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef textureMtl = createMtlTexture2DArray(1, 1, 3, MTLPixelFormatRGBA8Unorm);
482*8975f5c5SAndroid Build Coastguard Worker
483*8975f5c5SAndroid Build Coastguard Worker    GLubyte data0[4] = {93, 83, 75, 128};
484*8975f5c5SAndroid Build Coastguard Worker    [textureMtl replaceRegion:MTLRegionMake2D(0, 0, 1, 1)
485*8975f5c5SAndroid Build Coastguard Worker                  mipmapLevel:0
486*8975f5c5SAndroid Build Coastguard Worker                        slice:0
487*8975f5c5SAndroid Build Coastguard Worker                    withBytes:data0
488*8975f5c5SAndroid Build Coastguard Worker                  bytesPerRow:4
489*8975f5c5SAndroid Build Coastguard Worker                bytesPerImage:4];
490*8975f5c5SAndroid Build Coastguard Worker    GLubyte data1[4] = {7, 51, 197, 231};
491*8975f5c5SAndroid Build Coastguard Worker    [textureMtl replaceRegion:MTLRegionMake2D(0, 0, 1, 1)
492*8975f5c5SAndroid Build Coastguard Worker                  mipmapLevel:0
493*8975f5c5SAndroid Build Coastguard Worker                        slice:1
494*8975f5c5SAndroid Build Coastguard Worker                    withBytes:data1
495*8975f5c5SAndroid Build Coastguard Worker                  bytesPerRow:4
496*8975f5c5SAndroid Build Coastguard Worker                bytesPerImage:4];
497*8975f5c5SAndroid Build Coastguard Worker    GLubyte data2[4] = {33, 51, 44, 33};
498*8975f5c5SAndroid Build Coastguard Worker    [textureMtl replaceRegion:MTLRegionMake2D(0, 0, 1, 1)
499*8975f5c5SAndroid Build Coastguard Worker                  mipmapLevel:0
500*8975f5c5SAndroid Build Coastguard Worker                        slice:2
501*8975f5c5SAndroid Build Coastguard Worker                    withBytes:data2
502*8975f5c5SAndroid Build Coastguard Worker                  bytesPerRow:4
503*8975f5c5SAndroid Build Coastguard Worker                bytesPerImage:4];
504*8975f5c5SAndroid Build Coastguard Worker
505*8975f5c5SAndroid Build Coastguard Worker    EGLDisplay display = getEGLWindow()->getDisplay();
506*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image0 =
507*8975f5c5SAndroid Build Coastguard Worker        eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
508*8975f5c5SAndroid Build Coastguard Worker                          reinterpret_cast<EGLClientBuffer>(textureMtl.get()), nullptr);
509*8975f5c5SAndroid Build Coastguard Worker    ASSERT_EGL_SUCCESS();
510*8975f5c5SAndroid Build Coastguard Worker    const EGLint attribs1[] = {EGL_METAL_TEXTURE_ARRAY_SLICE_ANGLE, 1, EGL_NONE};
511*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image1 =
512*8975f5c5SAndroid Build Coastguard Worker        eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
513*8975f5c5SAndroid Build Coastguard Worker                          reinterpret_cast<EGLClientBuffer>(textureMtl.get()), attribs1);
514*8975f5c5SAndroid Build Coastguard Worker    ASSERT_EGL_SUCCESS();
515*8975f5c5SAndroid Build Coastguard Worker    const EGLint attribs2[] = {EGL_METAL_TEXTURE_ARRAY_SLICE_ANGLE, 2, EGL_NONE};
516*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image2 =
517*8975f5c5SAndroid Build Coastguard Worker        eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
518*8975f5c5SAndroid Build Coastguard Worker                          reinterpret_cast<EGLClientBuffer>(textureMtl.get()), attribs2);
519*8975f5c5SAndroid Build Coastguard Worker    ASSERT_EGL_SUCCESS();
520*8975f5c5SAndroid Build Coastguard Worker
521*8975f5c5SAndroid Build Coastguard Worker    GLTexture targetTexture;
522*8975f5c5SAndroid Build Coastguard Worker    glBindTexture(GL_TEXTURE_2D, targetTexture);
523*8975f5c5SAndroid Build Coastguard Worker    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image0);
524*8975f5c5SAndroid Build Coastguard Worker    verifyResults2D(targetTexture, data0);
525*8975f5c5SAndroid Build Coastguard Worker    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image1);
526*8975f5c5SAndroid Build Coastguard Worker    verifyResults2D(targetTexture, data1);
527*8975f5c5SAndroid Build Coastguard Worker    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image2);
528*8975f5c5SAndroid Build Coastguard Worker    verifyResults2D(targetTexture, data2);
529*8975f5c5SAndroid Build Coastguard Worker    eglDestroyImageKHR(display, image0);
530*8975f5c5SAndroid Build Coastguard Worker    eglDestroyImageKHR(display, image1);
531*8975f5c5SAndroid Build Coastguard Worker    eglDestroyImageKHR(display, image2);
532*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
533*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EGL_SUCCESS();
534*8975f5c5SAndroid Build Coastguard Worker}
535*8975f5c5SAndroid Build Coastguard Worker
536*8975f5c5SAndroid Build Coastguard Worker// Test that bound slice to EGLImage is not affected by releasing the source texture.
537*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, SourceMetalTarget2DArrayReleasedSourceOk)
538*8975f5c5SAndroid Build Coastguard Worker{
539*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
540*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
541*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef textureMtl = createMtlTexture2DArray(1, 1, 3, MTLPixelFormatRGBA8Unorm);
542*8975f5c5SAndroid Build Coastguard Worker
543*8975f5c5SAndroid Build Coastguard Worker    GLubyte data1[4] = {7, 51, 197, 231};
544*8975f5c5SAndroid Build Coastguard Worker    [textureMtl replaceRegion:MTLRegionMake2D(0, 0, 1, 1)
545*8975f5c5SAndroid Build Coastguard Worker                  mipmapLevel:0
546*8975f5c5SAndroid Build Coastguard Worker                        slice:1
547*8975f5c5SAndroid Build Coastguard Worker                    withBytes:data1
548*8975f5c5SAndroid Build Coastguard Worker                  bytesPerRow:4
549*8975f5c5SAndroid Build Coastguard Worker                bytesPerImage:4];
550*8975f5c5SAndroid Build Coastguard Worker
551*8975f5c5SAndroid Build Coastguard Worker    EGLDisplay display      = getEGLWindow()->getDisplay();
552*8975f5c5SAndroid Build Coastguard Worker    const EGLint attribs1[] = {EGL_METAL_TEXTURE_ARRAY_SLICE_ANGLE, 1, EGL_NONE};
553*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image1 =
554*8975f5c5SAndroid Build Coastguard Worker        eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
555*8975f5c5SAndroid Build Coastguard Worker                          reinterpret_cast<EGLClientBuffer>(textureMtl.get()), attribs1);
556*8975f5c5SAndroid Build Coastguard Worker    ASSERT_EGL_SUCCESS();
557*8975f5c5SAndroid Build Coastguard Worker    // This is being tested: release the source texture but the slice keeps working.
558*8975f5c5SAndroid Build Coastguard Worker    textureMtl = {};
559*8975f5c5SAndroid Build Coastguard Worker    GLTexture targetTexture;
560*8975f5c5SAndroid Build Coastguard Worker    glBindTexture(GL_TEXTURE_2D, targetTexture);
561*8975f5c5SAndroid Build Coastguard Worker    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image1);
562*8975f5c5SAndroid Build Coastguard Worker    verifyResults2D(targetTexture, data1);
563*8975f5c5SAndroid Build Coastguard Worker    eglDestroyImageKHR(display, image1);
564*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
565*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EGL_SUCCESS();
566*8975f5c5SAndroid Build Coastguard Worker}
567*8975f5c5SAndroid Build Coastguard Worker
568*8975f5c5SAndroid Build Coastguard Worker// Tests that OpenGL can draw to a texture bound with Metal texture.
569*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, DrawMetalTarget2D)
570*8975f5c5SAndroid Build Coastguard Worker{
571*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
572*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
573*8975f5c5SAndroid Build Coastguard Worker
574*8975f5c5SAndroid Build Coastguard Worker    EGLDisplay display = getEGLWindow()->getDisplay();
575*8975f5c5SAndroid Build Coastguard Worker
576*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef textureMtl = createMtlTexture2D(1, 1, MTLPixelFormatRGBA8Unorm);
577*8975f5c5SAndroid Build Coastguard Worker    [textureMtl replaceRegion:MTLRegionMake2D(0, 0, 1, 1)
578*8975f5c5SAndroid Build Coastguard Worker                  mipmapLevel:0
579*8975f5c5SAndroid Build Coastguard Worker                        slice:0
580*8975f5c5SAndroid Build Coastguard Worker                    withBytes:GLColor::red.data()
581*8975f5c5SAndroid Build Coastguard Worker                  bytesPerRow:4
582*8975f5c5SAndroid Build Coastguard Worker                bytesPerImage:4];
583*8975f5c5SAndroid Build Coastguard Worker
584*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image =
585*8975f5c5SAndroid Build Coastguard Worker        eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
586*8975f5c5SAndroid Build Coastguard Worker                          reinterpret_cast<EGLClientBuffer>(textureMtl.get()), nullptr);
587*8975f5c5SAndroid Build Coastguard Worker    ASSERT_EGL_SUCCESS();
588*8975f5c5SAndroid Build Coastguard Worker
589*8975f5c5SAndroid Build Coastguard Worker    GLTexture texture;
590*8975f5c5SAndroid Build Coastguard Worker    glBindTexture(GL_TEXTURE_2D, texture);
591*8975f5c5SAndroid Build Coastguard Worker    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
592*8975f5c5SAndroid Build Coastguard Worker
593*8975f5c5SAndroid Build Coastguard Worker    GLFramebuffer targetFbo;
594*8975f5c5SAndroid Build Coastguard Worker    glBindFramebuffer(GL_FRAMEBUFFER, targetFbo);
595*8975f5c5SAndroid Build Coastguard Worker    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
596*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
597*8975f5c5SAndroid Build Coastguard Worker
598*8975f5c5SAndroid Build Coastguard Worker    glViewport(0, 0, 1, 1);
599*8975f5c5SAndroid Build Coastguard Worker    drawColorQuad(GLColor::magenta);
600*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
601*8975f5c5SAndroid Build Coastguard Worker    eglDestroyImageKHR(display, image);
602*8975f5c5SAndroid Build Coastguard Worker    eglWaitUntilWorkScheduledANGLE(display);
603*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
604*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EGL_SUCCESS();
605*8975f5c5SAndroid Build Coastguard Worker
606*8975f5c5SAndroid Build Coastguard Worker    GLColor result;
607*8975f5c5SAndroid Build Coastguard Worker    getTextureSliceBytes(textureMtl, 4, MTLRegionMake2D(0, 0, 1, 1), 0, 0, {result.data(), 4});
608*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EQ(result, GLColor::magenta);
609*8975f5c5SAndroid Build Coastguard Worker}
610*8975f5c5SAndroid Build Coastguard Worker
611*8975f5c5SAndroid Build Coastguard Worker// Tests that OpenGL can draw to a texture bound with Metal texture slice.
612*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, DrawMetalTarget2DArray)
613*8975f5c5SAndroid Build Coastguard Worker{
614*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
615*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
616*8975f5c5SAndroid Build Coastguard Worker
617*8975f5c5SAndroid Build Coastguard Worker    EGLDisplay display = getEGLWindow()->getDisplay();
618*8975f5c5SAndroid Build Coastguard Worker
619*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef textureMtl = createMtlTexture2DArray(1, 1, 2, MTLPixelFormatRGBA8Unorm);
620*8975f5c5SAndroid Build Coastguard Worker    [textureMtl replaceRegion:MTLRegionMake2D(0, 0, 1, 1)
621*8975f5c5SAndroid Build Coastguard Worker                  mipmapLevel:0
622*8975f5c5SAndroid Build Coastguard Worker                        slice:0
623*8975f5c5SAndroid Build Coastguard Worker                    withBytes:GLColor::red.data()
624*8975f5c5SAndroid Build Coastguard Worker                  bytesPerRow:4
625*8975f5c5SAndroid Build Coastguard Worker                bytesPerImage:4];
626*8975f5c5SAndroid Build Coastguard Worker    [textureMtl replaceRegion:MTLRegionMake2D(0, 0, 1, 1)
627*8975f5c5SAndroid Build Coastguard Worker                  mipmapLevel:0
628*8975f5c5SAndroid Build Coastguard Worker                        slice:1
629*8975f5c5SAndroid Build Coastguard Worker                    withBytes:GLColor::red.data()
630*8975f5c5SAndroid Build Coastguard Worker                  bytesPerRow:4
631*8975f5c5SAndroid Build Coastguard Worker                bytesPerImage:4];
632*8975f5c5SAndroid Build Coastguard Worker
633*8975f5c5SAndroid Build Coastguard Worker    const EGLint attribs[] = {EGL_METAL_TEXTURE_ARRAY_SLICE_ANGLE, 1, EGL_NONE};
634*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image =
635*8975f5c5SAndroid Build Coastguard Worker        eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
636*8975f5c5SAndroid Build Coastguard Worker                          reinterpret_cast<EGLClientBuffer>(textureMtl.get()), attribs);
637*8975f5c5SAndroid Build Coastguard Worker    ASSERT_EGL_SUCCESS();
638*8975f5c5SAndroid Build Coastguard Worker
639*8975f5c5SAndroid Build Coastguard Worker    GLTexture texture;
640*8975f5c5SAndroid Build Coastguard Worker    glBindTexture(GL_TEXTURE_2D, texture);
641*8975f5c5SAndroid Build Coastguard Worker    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
642*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
643*8975f5c5SAndroid Build Coastguard Worker    GLFramebuffer targetFbo;
644*8975f5c5SAndroid Build Coastguard Worker    glBindFramebuffer(GL_FRAMEBUFFER, targetFbo);
645*8975f5c5SAndroid Build Coastguard Worker    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
646*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
647*8975f5c5SAndroid Build Coastguard Worker
648*8975f5c5SAndroid Build Coastguard Worker    glViewport(0, 0, 1, 1);
649*8975f5c5SAndroid Build Coastguard Worker    drawColorQuad(GLColor::magenta);
650*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
651*8975f5c5SAndroid Build Coastguard Worker    eglDestroyImageKHR(display, image);
652*8975f5c5SAndroid Build Coastguard Worker    eglWaitUntilWorkScheduledANGLE(display);
653*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
654*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EGL_SUCCESS();
655*8975f5c5SAndroid Build Coastguard Worker
656*8975f5c5SAndroid Build Coastguard Worker    GLColor result;
657*8975f5c5SAndroid Build Coastguard Worker    getTextureSliceBytes(textureMtl, 4, MTLRegionMake2D(0, 0, 1, 1), 0, 1, {result.data(), 4});
658*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EQ(result, GLColor::magenta);
659*8975f5c5SAndroid Build Coastguard Worker}
660*8975f5c5SAndroid Build Coastguard Worker
661*8975f5c5SAndroid Build Coastguard Worker// Tests that OpenGL can blit to a texture bound with Metal texture slice.
662*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, BlitMetalTarget2DArray)
663*8975f5c5SAndroid Build Coastguard Worker{
664*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
665*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
666*8975f5c5SAndroid Build Coastguard Worker
667*8975f5c5SAndroid Build Coastguard Worker    EGLDisplay display = getEGLWindow()->getDisplay();
668*8975f5c5SAndroid Build Coastguard Worker
669*8975f5c5SAndroid Build Coastguard Worker    GLTexture colorBuffer;
670*8975f5c5SAndroid Build Coastguard Worker    glBindTexture(GL_TEXTURE_2D, colorBuffer);
671*8975f5c5SAndroid Build Coastguard Worker    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
672*8975f5c5SAndroid Build Coastguard Worker    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
673*8975f5c5SAndroid Build Coastguard Worker    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
674*8975f5c5SAndroid Build Coastguard Worker    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, GLColor::green.data());
675*8975f5c5SAndroid Build Coastguard Worker    glTexSubImage2D(GL_TEXTURE_2D, 0, 1, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
676*8975f5c5SAndroid Build Coastguard Worker                    GLColor::yellow.data());
677*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
678*8975f5c5SAndroid Build Coastguard Worker
679*8975f5c5SAndroid Build Coastguard Worker    GLFramebuffer sourceFbo;
680*8975f5c5SAndroid Build Coastguard Worker    glBindFramebuffer(GL_FRAMEBUFFER, sourceFbo);
681*8975f5c5SAndroid Build Coastguard Worker    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorBuffer, 0);
682*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
683*8975f5c5SAndroid Build Coastguard Worker
684*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef textureMtl = createMtlTexture2DArray(1, 1, 2, MTLPixelFormatRGBA8Unorm);
685*8975f5c5SAndroid Build Coastguard Worker    [textureMtl replaceRegion:MTLRegionMake2D(0, 0, 1, 1)
686*8975f5c5SAndroid Build Coastguard Worker                  mipmapLevel:0
687*8975f5c5SAndroid Build Coastguard Worker                        slice:0
688*8975f5c5SAndroid Build Coastguard Worker                    withBytes:GLColor::red.data()
689*8975f5c5SAndroid Build Coastguard Worker                  bytesPerRow:4
690*8975f5c5SAndroid Build Coastguard Worker                bytesPerImage:4];
691*8975f5c5SAndroid Build Coastguard Worker    [textureMtl replaceRegion:MTLRegionMake2D(0, 0, 1, 1)
692*8975f5c5SAndroid Build Coastguard Worker                  mipmapLevel:0
693*8975f5c5SAndroid Build Coastguard Worker                        slice:1
694*8975f5c5SAndroid Build Coastguard Worker                    withBytes:GLColor::red.data()
695*8975f5c5SAndroid Build Coastguard Worker                  bytesPerRow:4
696*8975f5c5SAndroid Build Coastguard Worker                bytesPerImage:4];
697*8975f5c5SAndroid Build Coastguard Worker
698*8975f5c5SAndroid Build Coastguard Worker    for (int slice = 0; slice < 2; ++slice)
699*8975f5c5SAndroid Build Coastguard Worker    {
700*8975f5c5SAndroid Build Coastguard Worker        const EGLint attribs[] = {EGL_METAL_TEXTURE_ARRAY_SLICE_ANGLE, slice, EGL_NONE};
701*8975f5c5SAndroid Build Coastguard Worker        EGLImageKHR image =
702*8975f5c5SAndroid Build Coastguard Worker            eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
703*8975f5c5SAndroid Build Coastguard Worker                              reinterpret_cast<EGLClientBuffer>(textureMtl.get()), attribs);
704*8975f5c5SAndroid Build Coastguard Worker        ASSERT_EGL_SUCCESS();
705*8975f5c5SAndroid Build Coastguard Worker
706*8975f5c5SAndroid Build Coastguard Worker        GLTexture texture;
707*8975f5c5SAndroid Build Coastguard Worker        glBindTexture(GL_TEXTURE_2D, texture);
708*8975f5c5SAndroid Build Coastguard Worker        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
709*8975f5c5SAndroid Build Coastguard Worker        glBindFramebuffer(GL_FRAMEBUFFER, 0);
710*8975f5c5SAndroid Build Coastguard Worker        verifyResults2D(texture, GLColor::red.data());
711*8975f5c5SAndroid Build Coastguard Worker        EXPECT_GL_NO_ERROR();
712*8975f5c5SAndroid Build Coastguard Worker
713*8975f5c5SAndroid Build Coastguard Worker        GLFramebuffer targetFbo;
714*8975f5c5SAndroid Build Coastguard Worker        glBindFramebuffer(GL_FRAMEBUFFER, targetFbo);
715*8975f5c5SAndroid Build Coastguard Worker        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
716*8975f5c5SAndroid Build Coastguard Worker        EXPECT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
717*8975f5c5SAndroid Build Coastguard Worker
718*8975f5c5SAndroid Build Coastguard Worker        glBindFramebuffer(GL_READ_FRAMEBUFFER_ANGLE, sourceFbo);
719*8975f5c5SAndroid Build Coastguard Worker        glBindFramebuffer(GL_DRAW_FRAMEBUFFER_ANGLE, targetFbo);
720*8975f5c5SAndroid Build Coastguard Worker        glBlitFramebufferANGLE(slice, 0, slice + 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
721*8975f5c5SAndroid Build Coastguard Worker        EXPECT_GL_NO_ERROR();
722*8975f5c5SAndroid Build Coastguard Worker
723*8975f5c5SAndroid Build Coastguard Worker        glBindFramebuffer(GL_FRAMEBUFFER, 0);
724*8975f5c5SAndroid Build Coastguard Worker        verifyResults2D(texture, slice == 0 ? GLColor::green.data() : GLColor::yellow.data());
725*8975f5c5SAndroid Build Coastguard Worker        eglDestroyImageKHR(display, image);
726*8975f5c5SAndroid Build Coastguard Worker        EXPECT_GL_NO_ERROR();
727*8975f5c5SAndroid Build Coastguard Worker        EXPECT_EGL_SUCCESS();
728*8975f5c5SAndroid Build Coastguard Worker    }
729*8975f5c5SAndroid Build Coastguard Worker    eglWaitUntilWorkScheduledANGLE(display);
730*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EGL_SUCCESS();
731*8975f5c5SAndroid Build Coastguard Worker
732*8975f5c5SAndroid Build Coastguard Worker    GLColor result;
733*8975f5c5SAndroid Build Coastguard Worker    getTextureSliceBytes(textureMtl, 4, MTLRegionMake2D(0, 0, 1, 1), 0, 0, {result.data(), 4});
734*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EQ(result, GLColor::green);
735*8975f5c5SAndroid Build Coastguard Worker    getTextureSliceBytes(textureMtl, 4, MTLRegionMake2D(0, 0, 1, 1), 0, 1, {result.data(), 4});
736*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EQ(result, GLColor::yellow);
737*8975f5c5SAndroid Build Coastguard Worker}
738*8975f5c5SAndroid Build Coastguard Worker
739*8975f5c5SAndroid Build Coastguard Worker// Tests that OpenGL can override the internal format for a texture bound with
740*8975f5c5SAndroid Build Coastguard Worker// Metal texture.
741*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, OverrideMetalTextureInternalFormat)
742*8975f5c5SAndroid Build Coastguard Worker{
743*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
744*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
745*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(hasDepth24Stencil8PixelFormat());
746*8975f5c5SAndroid Build Coastguard Worker
747*8975f5c5SAndroid Build Coastguard Worker    EGLDisplay display = getEGLWindow()->getDisplay();
748*8975f5c5SAndroid Build Coastguard Worker
749*8975f5c5SAndroid Build Coastguard Worker    // On iOS devices, GL_DEPTH24_STENCIL8 is unavailable and is interally converted into
750*8975f5c5SAndroid Build Coastguard Worker    // GL_DEPTH32F_STENCIL8. This tests the ability to attach MTLPixelFormatDepth32Float_Stencil8
751*8975f5c5SAndroid Build Coastguard Worker    // and have GL treat it as GL_DEPTH24_STENCIL8 instead of GL_DEPTH32F_STENCIL8.
752*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef textureMtl =
753*8975f5c5SAndroid Build Coastguard Worker        createMtlTexture2DArray(1, 1, 1, MTLPixelFormatDepth32Float_Stencil8);
754*8975f5c5SAndroid Build Coastguard Worker    const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_DEPTH24_STENCIL8, EGL_NONE};
755*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image =
756*8975f5c5SAndroid Build Coastguard Worker        eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
757*8975f5c5SAndroid Build Coastguard Worker                          reinterpret_cast<EGLClientBuffer>(textureMtl.get()), attribs);
758*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EGL_SUCCESS();
759*8975f5c5SAndroid Build Coastguard Worker    EXPECT_NE(image, nullptr);
760*8975f5c5SAndroid Build Coastguard Worker}
761*8975f5c5SAndroid Build Coastguard Worker
762*8975f5c5SAndroid Build Coastguard Worker// Tests that OpenGL can override the internal format for a texture bound with
763*8975f5c5SAndroid Build Coastguard Worker// Metal texture and that rendering to the texture is successful.
764*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, RenderingTest)
765*8975f5c5SAndroid Build Coastguard Worker{
766*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
767*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
768*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(hasDepth24Stencil8PixelFormat());
769*8975f5c5SAndroid Build Coastguard Worker
770*8975f5c5SAndroid Build Coastguard Worker    EGLDisplay display = getEGLWindow()->getDisplay();
771*8975f5c5SAndroid Build Coastguard Worker
772*8975f5c5SAndroid Build Coastguard Worker    const int bufferSize = 32;
773*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef textureMtl =
774*8975f5c5SAndroid Build Coastguard Worker        createMtlTexture2DArray(bufferSize, bufferSize, 1, MTLPixelFormatDepth32Float_Stencil8);
775*8975f5c5SAndroid Build Coastguard Worker    const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_DEPTH24_STENCIL8, EGL_NONE};
776*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image =
777*8975f5c5SAndroid Build Coastguard Worker        eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
778*8975f5c5SAndroid Build Coastguard Worker                          reinterpret_cast<EGLClientBuffer>(textureMtl.get()), attribs);
779*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EGL_SUCCESS();
780*8975f5c5SAndroid Build Coastguard Worker    EXPECT_NE(image, nullptr);
781*8975f5c5SAndroid Build Coastguard Worker
782*8975f5c5SAndroid Build Coastguard Worker    GLRenderbuffer colorBuffer;
783*8975f5c5SAndroid Build Coastguard Worker    glBindRenderbuffer(GL_RENDERBUFFER, colorBuffer);
784*8975f5c5SAndroid Build Coastguard Worker    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, bufferSize, bufferSize);
785*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
786*8975f5c5SAndroid Build Coastguard Worker
787*8975f5c5SAndroid Build Coastguard Worker    GLRenderbuffer depthStencilBuffer;
788*8975f5c5SAndroid Build Coastguard Worker    glBindRenderbuffer(GL_RENDERBUFFER, depthStencilBuffer);
789*8975f5c5SAndroid Build Coastguard Worker    glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, image);
790*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
791*8975f5c5SAndroid Build Coastguard Worker
792*8975f5c5SAndroid Build Coastguard Worker    GLFramebuffer fb;
793*8975f5c5SAndroid Build Coastguard Worker    glBindFramebuffer(GL_FRAMEBUFFER, fb);
794*8975f5c5SAndroid Build Coastguard Worker    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorBuffer);
795*8975f5c5SAndroid Build Coastguard Worker    if (getClientMajorVersion() >= 3)
796*8975f5c5SAndroid Build Coastguard Worker    {
797*8975f5c5SAndroid Build Coastguard Worker        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
798*8975f5c5SAndroid Build Coastguard Worker                                  depthStencilBuffer);
799*8975f5c5SAndroid Build Coastguard Worker    }
800*8975f5c5SAndroid Build Coastguard Worker    else
801*8975f5c5SAndroid Build Coastguard Worker    {
802*8975f5c5SAndroid Build Coastguard Worker        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
803*8975f5c5SAndroid Build Coastguard Worker                                  depthStencilBuffer);
804*8975f5c5SAndroid Build Coastguard Worker        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
805*8975f5c5SAndroid Build Coastguard Worker                                  depthStencilBuffer);
806*8975f5c5SAndroid Build Coastguard Worker    }
807*8975f5c5SAndroid Build Coastguard Worker
808*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
809*8975f5c5SAndroid Build Coastguard Worker    ASSERT_GL_FRAMEBUFFER_COMPLETE(GL_FRAMEBUFFER);
810*8975f5c5SAndroid Build Coastguard Worker
811*8975f5c5SAndroid Build Coastguard Worker    glClearColor(1.f, 0.f, 0.f, 1.f);
812*8975f5c5SAndroid Build Coastguard Worker    glClearDepthf(1.f);
813*8975f5c5SAndroid Build Coastguard Worker    glClearStencil(0x55);
814*8975f5c5SAndroid Build Coastguard Worker    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
815*8975f5c5SAndroid Build Coastguard Worker    EXPECT_GL_NO_ERROR();
816*8975f5c5SAndroid Build Coastguard Worker
817*8975f5c5SAndroid Build Coastguard Worker    glEnable(GL_DEPTH_TEST);
818*8975f5c5SAndroid Build Coastguard Worker    glDepthFunc(GL_LESS);
819*8975f5c5SAndroid Build Coastguard Worker
820*8975f5c5SAndroid Build Coastguard Worker    glEnable(GL_STENCIL_TEST);
821*8975f5c5SAndroid Build Coastguard Worker    glStencilFunc(GL_EQUAL, 0x55, 0xFF);
822*8975f5c5SAndroid Build Coastguard Worker    glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
823*8975f5c5SAndroid Build Coastguard Worker    glStencilMask(0xFF);
824*8975f5c5SAndroid Build Coastguard Worker
825*8975f5c5SAndroid Build Coastguard Worker    // Draw green.
826*8975f5c5SAndroid Build Coastguard Worker    ANGLE_GL_PROGRAM(drawGreen, essl1_shaders::vs::Simple(), essl1_shaders::fs::Green());
827*8975f5c5SAndroid Build Coastguard Worker    drawQuad(drawGreen, essl1_shaders::PositionAttrib(), 0.95f);
828*8975f5c5SAndroid Build Coastguard Worker
829*8975f5c5SAndroid Build Coastguard Worker    // Verify that green was drawn.
830*8975f5c5SAndroid Build Coastguard Worker    EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green);
831*8975f5c5SAndroid Build Coastguard Worker    EXPECT_PIXEL_COLOR_EQ(0, bufferSize - 1, GLColor::green);
832*8975f5c5SAndroid Build Coastguard Worker    EXPECT_PIXEL_COLOR_EQ(bufferSize - 1, 0, GLColor::green);
833*8975f5c5SAndroid Build Coastguard Worker    EXPECT_PIXEL_COLOR_EQ(bufferSize - 1, bufferSize - 1, GLColor::green);
834*8975f5c5SAndroid Build Coastguard Worker
835*8975f5c5SAndroid Build Coastguard Worker    eglDestroyImageKHR(display, image);
836*8975f5c5SAndroid Build Coastguard Worker}
837*8975f5c5SAndroid Build Coastguard Worker
838*8975f5c5SAndroid Build Coastguard Worker// Tests that OpenGL override the with a bad internal format for a texture bound
839*8975f5c5SAndroid Build Coastguard Worker// with Metal texture fails.
840*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, OverrideMetalTextureInternalFormatBadFormat)
841*8975f5c5SAndroid Build Coastguard Worker{
842*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
843*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
844*8975f5c5SAndroid Build Coastguard Worker
845*8975f5c5SAndroid Build Coastguard Worker    EGLDisplay display = getEGLWindow()->getDisplay();
846*8975f5c5SAndroid Build Coastguard Worker
847*8975f5c5SAndroid Build Coastguard Worker    // On iOS devices, GL_DEPTH24_STENCIL8 is unavailable and is interally converted into
848*8975f5c5SAndroid Build Coastguard Worker    // GL_DEPTH32F_STENCIL8. This tests the ability to attach MTLPixelFormatDepth32Float_Stencil8
849*8975f5c5SAndroid Build Coastguard Worker    // and have GL treat it as GL_DEPTH24_STENCIL8 instead of GL_DEPTH32F_STENCIL8.
850*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef textureMtl =
851*8975f5c5SAndroid Build Coastguard Worker        createMtlTexture2DArray(1, 1, 1, MTLPixelFormatDepth32Float_Stencil8);
852*8975f5c5SAndroid Build Coastguard Worker    const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_TRIANGLES, EGL_NONE};
853*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image =
854*8975f5c5SAndroid Build Coastguard Worker        eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
855*8975f5c5SAndroid Build Coastguard Worker                          reinterpret_cast<EGLClientBuffer>(textureMtl.get()), attribs);
856*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
857*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EQ(image, nullptr);
858*8975f5c5SAndroid Build Coastguard Worker}
859*8975f5c5SAndroid Build Coastguard Worker
860*8975f5c5SAndroid Build Coastguard Worker// Tests that OpenGL override the with an incompatible internal format for a texture bound
861*8975f5c5SAndroid Build Coastguard Worker// with Metal texture fails.
862*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, OverrideMetalTextureInternalFormatIncompatibleFormat)
863*8975f5c5SAndroid Build Coastguard Worker{
864*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
865*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
866*8975f5c5SAndroid Build Coastguard Worker
867*8975f5c5SAndroid Build Coastguard Worker    EGLDisplay display = getEGLWindow()->getDisplay();
868*8975f5c5SAndroid Build Coastguard Worker
869*8975f5c5SAndroid Build Coastguard Worker    // On iOS devices, GL_DEPTH24_STENCIL8 is unavailable and is interally converted into
870*8975f5c5SAndroid Build Coastguard Worker    // GL_DEPTH32F_STENCIL8. This tests the ability to attach MTLPixelFormatDepth32Float_Stencil8
871*8975f5c5SAndroid Build Coastguard Worker    // and have GL treat it as GL_DEPTH24_STENCIL8 instead of GL_DEPTH32F_STENCIL8.
872*8975f5c5SAndroid Build Coastguard Worker    ScopedMetalTextureRef textureMtl =
873*8975f5c5SAndroid Build Coastguard Worker        createMtlTexture2DArray(1, 1, 1, MTLPixelFormatDepth32Float_Stencil8);
874*8975f5c5SAndroid Build Coastguard Worker    const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_RGBA8, EGL_NONE};
875*8975f5c5SAndroid Build Coastguard Worker    EGLImageKHR image =
876*8975f5c5SAndroid Build Coastguard Worker        eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
877*8975f5c5SAndroid Build Coastguard Worker                          reinterpret_cast<EGLClientBuffer>(textureMtl.get()), attribs);
878*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE);
879*8975f5c5SAndroid Build Coastguard Worker    EXPECT_EQ(image, nullptr);
880*8975f5c5SAndroid Build Coastguard Worker}
881*8975f5c5SAndroid Build Coastguard Worker
882*8975f5c5SAndroid Build Coastguard Worker// Test this scenario:
883*8975f5c5SAndroid Build Coastguard Worker// Metal and GL share the same MTL texture (called texture1).
884*8975f5c5SAndroid Build Coastguard Worker// GL Context draws to texture1:
885*8975f5c5SAndroid Build Coastguard Worker// - draw.
886*8975f5c5SAndroid Build Coastguard Worker// - upload texture2
887*8975f5c5SAndroid Build Coastguard Worker// - draw using the texture2 as source.
888*8975f5c5SAndroid Build Coastguard Worker// - place a sync object.
889*8975f5c5SAndroid Build Coastguard Worker//
890*8975f5c5SAndroid Build Coastguard Worker// Metal reads the texture1:
891*8975f5c5SAndroid Build Coastguard Worker// - wait for the shared event sync object.
892*8975f5c5SAndroid Build Coastguard Worker// - copy the texture1 to a buffer.
893*8975f5c5SAndroid Build Coastguard Worker// - The buffer should contain color from texture2 after being uploaded.
894*8975f5c5SAndroid Build Coastguard Worker//
895*8975f5c5SAndroid Build Coastguard Worker// Previously this would cause a bug in Metal backend because texture upload would
896*8975f5c5SAndroid Build Coastguard Worker// create a new blit encoder in a middle of a render pass and the command buffer would mistrack the
897*8975f5c5SAndroid Build Coastguard Worker// ongoing render encoder. Thus making the metal sync object being placed incorrectly.
898*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageTestMetal, SharedEventSyncWhenThereIsTextureUploadBetweenDraws)
899*8975f5c5SAndroid Build Coastguard Worker{
900*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
901*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
902*8975f5c5SAndroid Build Coastguard Worker
903*8975f5c5SAndroid Build Coastguard Worker    EGLDisplay display1 = getEGLWindow()->getDisplay();
904*8975f5c5SAndroid Build Coastguard Worker
905*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3);
906*8975f5c5SAndroid Build Coastguard Worker    ANGLE_SKIP_TEST_IF(
907*8975f5c5SAndroid Build Coastguard Worker        !IsEGLDisplayExtensionEnabled(display1, "EGL_ANGLE_metal_shared_event_sync"));
908*8975f5c5SAndroid Build Coastguard Worker
909*8975f5c5SAndroid Build Coastguard Worker    @autoreleasepool
910*8975f5c5SAndroid Build Coastguard Worker    {
911*8975f5c5SAndroid Build Coastguard Worker        // Create MTLTexture
912*8975f5c5SAndroid Build Coastguard Worker        constexpr int kSharedTextureSize = 1024;
913*8975f5c5SAndroid Build Coastguard Worker        ScopedMetalTextureRef textureMtl =
914*8975f5c5SAndroid Build Coastguard Worker            createMtlTexture2D(kSharedTextureSize, kSharedTextureSize, MTLPixelFormatR32Sint);
915*8975f5c5SAndroid Build Coastguard Worker
916*8975f5c5SAndroid Build Coastguard Worker        // Create SharedEvent
917*8975f5c5SAndroid Build Coastguard Worker        id<MTLDevice> deviceMtl           = getMtlDevice();
918*8975f5c5SAndroid Build Coastguard Worker        id<MTLSharedEvent> sharedEventMtl = CreateMetalSharedEvent(deviceMtl);
919*8975f5c5SAndroid Build Coastguard Worker
920*8975f5c5SAndroid Build Coastguard Worker        // -------------------------- Metal ---------------------------
921*8975f5c5SAndroid Build Coastguard Worker        // Create a buffer on Metal to store the final value.
922*8975f5c5SAndroid Build Coastguard Worker        ScopedMetalBufferRef dstBuffer(
923*8975f5c5SAndroid Build Coastguard Worker            [deviceMtl newBufferWithLength:sizeof(float) options:MTLResourceStorageModeShared]);
924*8975f5c5SAndroid Build Coastguard Worker        ScopedMetalCommandQueueRef commandQueue([deviceMtl newCommandQueue]);
925*8975f5c5SAndroid Build Coastguard Worker        id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer];
926*8975f5c5SAndroid Build Coastguard Worker
927*8975f5c5SAndroid Build Coastguard Worker        // Wait for drawing on GL context to finish on server side.
928*8975f5c5SAndroid Build Coastguard Worker        // Note: we issue a wait even before the draw calls are issued on GL context.
929*8975f5c5SAndroid Build Coastguard Worker        // GL context will issue a signaling later (see below).
930*8975f5c5SAndroid Build Coastguard Worker        constexpr uint64_t kSignalValue = 0xff;
931*8975f5c5SAndroid Build Coastguard Worker        [commandBuffer encodeWaitForEvent:sharedEventMtl value:kSignalValue];
932*8975f5c5SAndroid Build Coastguard Worker
933*8975f5c5SAndroid Build Coastguard Worker        // Copy a pixel from texture1 to dstBuffer
934*8975f5c5SAndroid Build Coastguard Worker        id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
935*8975f5c5SAndroid Build Coastguard Worker        [blitEncoder copyFromTexture:textureMtl
936*8975f5c5SAndroid Build Coastguard Worker                         sourceSlice:0
937*8975f5c5SAndroid Build Coastguard Worker                         sourceLevel:0
938*8975f5c5SAndroid Build Coastguard Worker                        sourceOrigin:MTLOriginMake(kSharedTextureSize - 1, kSharedTextureSize - 2,
939*8975f5c5SAndroid Build Coastguard Worker                                                   0)
940*8975f5c5SAndroid Build Coastguard Worker                          sourceSize:MTLSizeMake(1, 1, 1)
941*8975f5c5SAndroid Build Coastguard Worker                            toBuffer:dstBuffer
942*8975f5c5SAndroid Build Coastguard Worker                   destinationOffset:0
943*8975f5c5SAndroid Build Coastguard Worker              destinationBytesPerRow:sizeof(float) * kSharedTextureSize
944*8975f5c5SAndroid Build Coastguard Worker            destinationBytesPerImage:0];
945*8975f5c5SAndroid Build Coastguard Worker        [blitEncoder endEncoding];
946*8975f5c5SAndroid Build Coastguard Worker        [commandBuffer commit];
947*8975f5c5SAndroid Build Coastguard Worker
948*8975f5c5SAndroid Build Coastguard Worker        // -------------------------- GL context ---------------------------
949*8975f5c5SAndroid Build Coastguard Worker        constexpr int kNumValues = 1000;
950*8975f5c5SAndroid Build Coastguard Worker        // A deliberately slow shader that reads a texture many times then write
951*8975f5c5SAndroid Build Coastguard Worker        // the sum value to an ouput varible.
952*8975f5c5SAndroid Build Coastguard Worker        constexpr char kFS[] = R"(#version 300 es
953*8975f5c5SAndroid Build Coastguard Workerout highp ivec4 outColor;
954*8975f5c5SAndroid Build Coastguard Worker
955*8975f5c5SAndroid Build Coastguard Workeruniform highp isampler2D u_valuesTex;
956*8975f5c5SAndroid Build Coastguard Worker
957*8975f5c5SAndroid Build Coastguard Workervoid main()
958*8975f5c5SAndroid Build Coastguard Worker{
959*8975f5c5SAndroid Build Coastguard Worker    highp int value = 0;
960*8975f5c5SAndroid Build Coastguard Worker    for (int i = 0; i < 1000; ++i) {
961*8975f5c5SAndroid Build Coastguard Worker        highp float uCoords = (float(i) + 0.5) / float(1000);
962*8975f5c5SAndroid Build Coastguard Worker        value += textureLod(u_valuesTex, vec2(uCoords, 0.0), 0.0).r;
963*8975f5c5SAndroid Build Coastguard Worker    }
964*8975f5c5SAndroid Build Coastguard Worker
965*8975f5c5SAndroid Build Coastguard Worker    outColor = ivec4(value);
966*8975f5c5SAndroid Build Coastguard Worker})";
967*8975f5c5SAndroid Build Coastguard Worker
968*8975f5c5SAndroid Build Coastguard Worker        ANGLE_GL_PROGRAM(complexProgram, essl3_shaders::vs::Simple(), kFS);
969*8975f5c5SAndroid Build Coastguard Worker        GLint valuesTexLocation = glGetUniformLocation(complexProgram, "u_valuesTex");
970*8975f5c5SAndroid Build Coastguard Worker        ASSERT_NE(valuesTexLocation, -1);
971*8975f5c5SAndroid Build Coastguard Worker
972*8975f5c5SAndroid Build Coastguard Worker        // Create the shared texture from MTLTexture.
973*8975f5c5SAndroid Build Coastguard Worker        EGLImageKHR image =
974*8975f5c5SAndroid Build Coastguard Worker            eglCreateImageKHR(display1, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
975*8975f5c5SAndroid Build Coastguard Worker                              reinterpret_cast<EGLClientBuffer>(textureMtl.get()), kDefaultAttribs);
976*8975f5c5SAndroid Build Coastguard Worker        EXPECT_EGL_SUCCESS();
977*8975f5c5SAndroid Build Coastguard Worker        GLTexture texture1;
978*8975f5c5SAndroid Build Coastguard Worker        glBindTexture(GL_TEXTURE_2D, texture1);
979*8975f5c5SAndroid Build Coastguard Worker        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
980*8975f5c5SAndroid Build Coastguard Worker        EXPECT_GL_ERROR(GL_NO_ERROR);
981*8975f5c5SAndroid Build Coastguard Worker        glViewport(0, 0, kSharedTextureSize, kSharedTextureSize);
982*8975f5c5SAndroid Build Coastguard Worker
983*8975f5c5SAndroid Build Coastguard Worker        // Create texture holding multiple values to be accumulated in shader.
984*8975f5c5SAndroid Build Coastguard Worker        GLTexture texture2;
985*8975f5c5SAndroid Build Coastguard Worker        glBindTexture(GL_TEXTURE_2D, texture2);
986*8975f5c5SAndroid Build Coastguard Worker        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
987*8975f5c5SAndroid Build Coastguard Worker        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
988*8975f5c5SAndroid Build Coastguard Worker        glTexImage2D(GL_TEXTURE_2D, 0, GL_R32I, kNumValues, 1, 0, GL_RED_INTEGER, GL_INT, nullptr);
989*8975f5c5SAndroid Build Coastguard Worker        glFlush();
990*8975f5c5SAndroid Build Coastguard Worker        EXPECT_GL_ERROR(GL_NO_ERROR);
991*8975f5c5SAndroid Build Coastguard Worker
992*8975f5c5SAndroid Build Coastguard Worker        // Using GL context to draw to the texture1
993*8975f5c5SAndroid Build Coastguard Worker        glBindTexture(GL_TEXTURE_2D, texture1);
994*8975f5c5SAndroid Build Coastguard Worker        GLFramebuffer framebuffer1;
995*8975f5c5SAndroid Build Coastguard Worker        glBindFramebuffer(GL_FRAMEBUFFER, framebuffer1);
996*8975f5c5SAndroid Build Coastguard Worker        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture1, 0);
997*8975f5c5SAndroid Build Coastguard Worker
998*8975f5c5SAndroid Build Coastguard Worker        // First draw with initial color
999*8975f5c5SAndroid Build Coastguard Worker        {
1000*8975f5c5SAndroid Build Coastguard Worker            constexpr char kSimpleFS[] = R"(#version 300 es
1001*8975f5c5SAndroid Build Coastguard Workerout highp ivec4 outColor;
1002*8975f5c5SAndroid Build Coastguard Worker
1003*8975f5c5SAndroid Build Coastguard Workervoid main()
1004*8975f5c5SAndroid Build Coastguard Worker{
1005*8975f5c5SAndroid Build Coastguard Worker    outColor = ivec4(1);
1006*8975f5c5SAndroid Build Coastguard Worker})";
1007*8975f5c5SAndroid Build Coastguard Worker            ANGLE_GL_PROGRAM(colorProgram, angle::essl3_shaders::vs::Simple(), kSimpleFS);
1008*8975f5c5SAndroid Build Coastguard Worker            drawQuad(colorProgram, angle::essl3_shaders::PositionAttrib(), 0.5f);
1009*8975f5c5SAndroid Build Coastguard Worker        }
1010*8975f5c5SAndroid Build Coastguard Worker
1011*8975f5c5SAndroid Build Coastguard Worker        // Upload the texture2
1012*8975f5c5SAndroid Build Coastguard Worker        std::vector<int32_t> values(kNumValues);
1013*8975f5c5SAndroid Build Coastguard Worker        for (size_t i = 0; i < values.size(); ++i)
1014*8975f5c5SAndroid Build Coastguard Worker        {
1015*8975f5c5SAndroid Build Coastguard Worker            values[i] = i;
1016*8975f5c5SAndroid Build Coastguard Worker        }
1017*8975f5c5SAndroid Build Coastguard Worker        glBindTexture(GL_TEXTURE_2D, texture2);
1018*8975f5c5SAndroid Build Coastguard Worker        glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, kNumValues, 1, GL_RED_INTEGER, GL_INT,
1019*8975f5c5SAndroid Build Coastguard Worker                        values.data());
1020*8975f5c5SAndroid Build Coastguard Worker
1021*8975f5c5SAndroid Build Coastguard Worker        // 2nd draw call draw the texture2 to texture1.
1022*8975f5c5SAndroid Build Coastguard Worker        glUseProgram(complexProgram);
1023*8975f5c5SAndroid Build Coastguard Worker        drawQuad(complexProgram, angle::essl1_shaders::PositionAttrib(), 0.5f);
1024*8975f5c5SAndroid Build Coastguard Worker
1025*8975f5c5SAndroid Build Coastguard Worker        // Place a sync object on GL context's commands stream.
1026*8975f5c5SAndroid Build Coastguard Worker        EGLSync syncGL = CreateEGLSyncFromMetalSharedEvent(display1, sharedEventMtl, kSignalValue,
1027*8975f5c5SAndroid Build Coastguard Worker                                                           /*signaled=*/false);
1028*8975f5c5SAndroid Build Coastguard Worker        glFlush();
1029*8975f5c5SAndroid Build Coastguard Worker
1030*8975f5c5SAndroid Build Coastguard Worker        // -------------------------- Metal ---------------------------
1031*8975f5c5SAndroid Build Coastguard Worker        [commandBuffer waitUntilCompleted];
1032*8975f5c5SAndroid Build Coastguard Worker
1033*8975f5c5SAndroid Build Coastguard Worker        // Read dstBuffer
1034*8975f5c5SAndroid Build Coastguard Worker        const int32_t kExpectedSum = kNumValues * (kNumValues - 1) / 2;
1035*8975f5c5SAndroid Build Coastguard Worker        int32_t *mappedInts        = static_cast<int32_t *>(dstBuffer.get().contents);
1036*8975f5c5SAndroid Build Coastguard Worker        EXPECT_EQ(mappedInts[0], kExpectedSum);
1037*8975f5c5SAndroid Build Coastguard Worker
1038*8975f5c5SAndroid Build Coastguard Worker        eglDestroySync(display1, syncGL);
1039*8975f5c5SAndroid Build Coastguard Worker        eglDestroyImage(display1, image);
1040*8975f5c5SAndroid Build Coastguard Worker
1041*8975f5c5SAndroid Build Coastguard Worker    }  // @autoreleasepool
1042*8975f5c5SAndroid Build Coastguard Worker}
1043*8975f5c5SAndroid Build Coastguard Worker
1044*8975f5c5SAndroid Build Coastguard Workerclass ImageClearTestMetal : public ImageTestMetal
1045*8975f5c5SAndroid Build Coastguard Worker{
1046*8975f5c5SAndroid Build Coastguard Worker  protected:
1047*8975f5c5SAndroid Build Coastguard Worker    ImageClearTestMetal() : ImageTestMetal() {}
1048*8975f5c5SAndroid Build Coastguard Worker
1049*8975f5c5SAndroid Build Coastguard Worker    void RunUnsizedClearTest(MTLPixelFormat format)
1050*8975f5c5SAndroid Build Coastguard Worker    {
1051*8975f5c5SAndroid Build Coastguard Worker        ANGLE_SKIP_TEST_IF(!hasOESExt() || !hasBaseExt());
1052*8975f5c5SAndroid Build Coastguard Worker        ANGLE_SKIP_TEST_IF(!hasImageNativeMetalTextureExt());
1053*8975f5c5SAndroid Build Coastguard Worker
1054*8975f5c5SAndroid Build Coastguard Worker        EGLWindow *window  = getEGLWindow();
1055*8975f5c5SAndroid Build Coastguard Worker        EGLDisplay display = window->getDisplay();
1056*8975f5c5SAndroid Build Coastguard Worker
1057*8975f5c5SAndroid Build Coastguard Worker        window->makeCurrent();
1058*8975f5c5SAndroid Build Coastguard Worker
1059*8975f5c5SAndroid Build Coastguard Worker        const GLint bufferSize = 32;
1060*8975f5c5SAndroid Build Coastguard Worker        ScopedMetalTextureRef textureMtl =
1061*8975f5c5SAndroid Build Coastguard Worker            createMtlTexture2DArray(bufferSize, bufferSize, 1, format);
1062*8975f5c5SAndroid Build Coastguard Worker        EXPECT_TRUE(textureMtl);
1063*8975f5c5SAndroid Build Coastguard Worker
1064*8975f5c5SAndroid Build Coastguard Worker        EGLint internalFormat = GL_NONE;
1065*8975f5c5SAndroid Build Coastguard Worker        switch (format)
1066*8975f5c5SAndroid Build Coastguard Worker        {
1067*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatR8Unorm:
1068*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatR16Unorm:
1069*8975f5c5SAndroid Build Coastguard Worker                internalFormat = GL_RED_EXT;
1070*8975f5c5SAndroid Build Coastguard Worker                break;
1071*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatRG8Unorm:
1072*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatRG16Unorm:
1073*8975f5c5SAndroid Build Coastguard Worker                internalFormat = GL_RG_EXT;
1074*8975f5c5SAndroid Build Coastguard Worker                break;
1075*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatRGBA8Unorm:
1076*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatRGBA16Float:
1077*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatRGB10A2Unorm:
1078*8975f5c5SAndroid Build Coastguard Worker                internalFormat = GL_RGBA;
1079*8975f5c5SAndroid Build Coastguard Worker                break;
1080*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatRGBA8Unorm_sRGB:
1081*8975f5c5SAndroid Build Coastguard Worker                internalFormat = GL_SRGB_ALPHA_EXT;
1082*8975f5c5SAndroid Build Coastguard Worker                break;
1083*8975f5c5SAndroid Build Coastguard Worker            case MTLPixelFormatBGRA8Unorm:
1084*8975f5c5SAndroid Build Coastguard Worker                internalFormat = GL_BGRA_EXT;
1085*8975f5c5SAndroid Build Coastguard Worker                break;
1086*8975f5c5SAndroid Build Coastguard Worker            default:
1087*8975f5c5SAndroid Build Coastguard Worker                break;
1088*8975f5c5SAndroid Build Coastguard Worker        }
1089*8975f5c5SAndroid Build Coastguard Worker
1090*8975f5c5SAndroid Build Coastguard Worker        const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, internalFormat, EGL_NONE};
1091*8975f5c5SAndroid Build Coastguard Worker
1092*8975f5c5SAndroid Build Coastguard Worker        EGLImageKHR image =
1093*8975f5c5SAndroid Build Coastguard Worker            eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_METAL_TEXTURE_ANGLE,
1094*8975f5c5SAndroid Build Coastguard Worker                              reinterpret_cast<EGLClientBuffer>(textureMtl.get()), attribs);
1095*8975f5c5SAndroid Build Coastguard Worker        ASSERT_EGL_SUCCESS();
1096*8975f5c5SAndroid Build Coastguard Worker        ASSERT_NE(image, EGL_NO_IMAGE_KHR);
1097*8975f5c5SAndroid Build Coastguard Worker
1098*8975f5c5SAndroid Build Coastguard Worker        GLTexture texture;
1099*8975f5c5SAndroid Build Coastguard Worker        glBindTexture(GL_TEXTURE_2D, texture);
1100*8975f5c5SAndroid Build Coastguard Worker        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1101*8975f5c5SAndroid Build Coastguard Worker        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1102*8975f5c5SAndroid Build Coastguard Worker        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1103*8975f5c5SAndroid Build Coastguard Worker        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1104*8975f5c5SAndroid Build Coastguard Worker        EXPECT_GL_NO_ERROR();
1105*8975f5c5SAndroid Build Coastguard Worker
1106*8975f5c5SAndroid Build Coastguard Worker        glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
1107*8975f5c5SAndroid Build Coastguard Worker        EXPECT_GL_NO_ERROR();
1108*8975f5c5SAndroid Build Coastguard Worker
1109*8975f5c5SAndroid Build Coastguard Worker        GLFramebuffer fbo;
1110*8975f5c5SAndroid Build Coastguard Worker        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
1111*8975f5c5SAndroid Build Coastguard Worker        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
1112*8975f5c5SAndroid Build Coastguard Worker        EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER),
1113*8975f5c5SAndroid Build Coastguard Worker                  static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE));
1114*8975f5c5SAndroid Build Coastguard Worker        EXPECT_GL_NO_ERROR();
1115*8975f5c5SAndroid Build Coastguard Worker
1116*8975f5c5SAndroid Build Coastguard Worker        glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize));
1117*8975f5c5SAndroid Build Coastguard Worker        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
1118*8975f5c5SAndroid Build Coastguard Worker        glClear(GL_COLOR_BUFFER_BIT);
1119*8975f5c5SAndroid Build Coastguard Worker        ASSERT_GL_NO_ERROR();
1120*8975f5c5SAndroid Build Coastguard Worker
1121*8975f5c5SAndroid Build Coastguard Worker        if (format == MTLPixelFormatRGBA16Float)
1122*8975f5c5SAndroid Build Coastguard Worker        {
1123*8975f5c5SAndroid Build Coastguard Worker            EXPECT_PIXEL_32F_EQ(bufferSize / 2, bufferSize / 2, 1.0f, 1.0f, 1.0f, 1.0f);
1124*8975f5c5SAndroid Build Coastguard Worker        }
1125*8975f5c5SAndroid Build Coastguard Worker        else if (format == MTLPixelFormatR16Unorm)
1126*8975f5c5SAndroid Build Coastguard Worker        {
1127*8975f5c5SAndroid Build Coastguard Worker            EXPECT_PIXEL_16_NEAR(bufferSize / 2, bufferSize / 2, 65535, 0, 0, 65535, 0);
1128*8975f5c5SAndroid Build Coastguard Worker        }
1129*8975f5c5SAndroid Build Coastguard Worker        else if (format == MTLPixelFormatRG16Unorm)
1130*8975f5c5SAndroid Build Coastguard Worker        {
1131*8975f5c5SAndroid Build Coastguard Worker            EXPECT_PIXEL_16_NEAR(bufferSize / 2, bufferSize / 2, 65535, 65535, 0, 65535, 0);
1132*8975f5c5SAndroid Build Coastguard Worker        }
1133*8975f5c5SAndroid Build Coastguard Worker        else
1134*8975f5c5SAndroid Build Coastguard Worker        {
1135*8975f5c5SAndroid Build Coastguard Worker            GLuint readColor[4] = {0, 0, 0, 255};
1136*8975f5c5SAndroid Build Coastguard Worker            switch (format)
1137*8975f5c5SAndroid Build Coastguard Worker            {
1138*8975f5c5SAndroid Build Coastguard Worker                case MTLPixelFormatR8Unorm:
1139*8975f5c5SAndroid Build Coastguard Worker                    readColor[0] = 255;
1140*8975f5c5SAndroid Build Coastguard Worker                    break;
1141*8975f5c5SAndroid Build Coastguard Worker                case MTLPixelFormatRG8Unorm:
1142*8975f5c5SAndroid Build Coastguard Worker                    readColor[0] = readColor[1] = 255;
1143*8975f5c5SAndroid Build Coastguard Worker                    break;
1144*8975f5c5SAndroid Build Coastguard Worker                case MTLPixelFormatRGBA8Unorm:
1145*8975f5c5SAndroid Build Coastguard Worker                case MTLPixelFormatRGB10A2Unorm:
1146*8975f5c5SAndroid Build Coastguard Worker                case MTLPixelFormatRGBA16Float:
1147*8975f5c5SAndroid Build Coastguard Worker                case MTLPixelFormatRGBA8Unorm_sRGB:
1148*8975f5c5SAndroid Build Coastguard Worker                case MTLPixelFormatBGRA8Unorm:
1149*8975f5c5SAndroid Build Coastguard Worker                    readColor[0] = readColor[1] = readColor[2] = 255;
1150*8975f5c5SAndroid Build Coastguard Worker                    break;
1151*8975f5c5SAndroid Build Coastguard Worker                default:
1152*8975f5c5SAndroid Build Coastguard Worker                    break;
1153*8975f5c5SAndroid Build Coastguard Worker            }
1154*8975f5c5SAndroid Build Coastguard Worker            // Read back as GL_UNSIGNED_BYTE even though the texture might have more than 8bpc.
1155*8975f5c5SAndroid Build Coastguard Worker            EXPECT_PIXEL_EQ(bufferSize / 2, bufferSize / 2, readColor[0], readColor[1],
1156*8975f5c5SAndroid Build Coastguard Worker                            readColor[2], readColor[3]);
1157*8975f5c5SAndroid Build Coastguard Worker        }
1158*8975f5c5SAndroid Build Coastguard Worker    }
1159*8975f5c5SAndroid Build Coastguard Worker};
1160*8975f5c5SAndroid Build Coastguard Worker
1161*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageClearTestMetal, ClearUnsizedRGBA8)
1162*8975f5c5SAndroid Build Coastguard Worker{
1163*8975f5c5SAndroid Build Coastguard Worker    RunUnsizedClearTest(MTLPixelFormatRGBA8Unorm);
1164*8975f5c5SAndroid Build Coastguard Worker}
1165*8975f5c5SAndroid Build Coastguard Worker
1166*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageClearTestMetal, ClearUnsizedsRGBA8)
1167*8975f5c5SAndroid Build Coastguard Worker{
1168*8975f5c5SAndroid Build Coastguard Worker    RunUnsizedClearTest(MTLPixelFormatRGBA8Unorm_sRGB);
1169*8975f5c5SAndroid Build Coastguard Worker}
1170*8975f5c5SAndroid Build Coastguard Worker
1171*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageClearTestMetal, ClearUnsizedBGRA8)
1172*8975f5c5SAndroid Build Coastguard Worker{
1173*8975f5c5SAndroid Build Coastguard Worker    RunUnsizedClearTest(MTLPixelFormatBGRA8Unorm);
1174*8975f5c5SAndroid Build Coastguard Worker}
1175*8975f5c5SAndroid Build Coastguard Worker
1176*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageClearTestMetal, ClearUnsizedR8)
1177*8975f5c5SAndroid Build Coastguard Worker{
1178*8975f5c5SAndroid Build Coastguard Worker    RunUnsizedClearTest(MTLPixelFormatR8Unorm);
1179*8975f5c5SAndroid Build Coastguard Worker}
1180*8975f5c5SAndroid Build Coastguard Worker
1181*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageClearTestMetal, ClearUnsizedRG8)
1182*8975f5c5SAndroid Build Coastguard Worker{
1183*8975f5c5SAndroid Build Coastguard Worker    RunUnsizedClearTest(MTLPixelFormatRG8Unorm);
1184*8975f5c5SAndroid Build Coastguard Worker}
1185*8975f5c5SAndroid Build Coastguard Worker
1186*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageClearTestMetal, ClearUnsizedRGB10A2)
1187*8975f5c5SAndroid Build Coastguard Worker{
1188*8975f5c5SAndroid Build Coastguard Worker    RunUnsizedClearTest(MTLPixelFormatRGB10A2Unorm);
1189*8975f5c5SAndroid Build Coastguard Worker}
1190*8975f5c5SAndroid Build Coastguard Worker
1191*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageClearTestMetal, ClearUnsizedRGBAF16)
1192*8975f5c5SAndroid Build Coastguard Worker{
1193*8975f5c5SAndroid Build Coastguard Worker    RunUnsizedClearTest(MTLPixelFormatRGBA16Float);
1194*8975f5c5SAndroid Build Coastguard Worker}
1195*8975f5c5SAndroid Build Coastguard Worker
1196*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageClearTestMetal, ClearUnsizedR16)
1197*8975f5c5SAndroid Build Coastguard Worker{
1198*8975f5c5SAndroid Build Coastguard Worker    RunUnsizedClearTest(MTLPixelFormatR16Unorm);
1199*8975f5c5SAndroid Build Coastguard Worker}
1200*8975f5c5SAndroid Build Coastguard Worker
1201*8975f5c5SAndroid Build Coastguard WorkerTEST_P(ImageClearTestMetal, ClearUnsizedRG16)
1202*8975f5c5SAndroid Build Coastguard Worker{
1203*8975f5c5SAndroid Build Coastguard Worker    RunUnsizedClearTest(MTLPixelFormatRG16Unorm);
1204*8975f5c5SAndroid Build Coastguard Worker}
1205*8975f5c5SAndroid Build Coastguard Worker
1206*8975f5c5SAndroid Build Coastguard Worker// Use this to select which configurations (e.g. which renderer, which GLES major version) these
1207*8975f5c5SAndroid Build Coastguard Worker// tests should be run against.
1208*8975f5c5SAndroid Build Coastguard WorkerANGLE_INSTANTIATE_TEST(ImageTestMetal, ES2_METAL(), ES3_METAL());
1209*8975f5c5SAndroid Build Coastguard WorkerANGLE_INSTANTIATE_TEST(ImageClearTestMetal, ES2_METAL(), ES3_METAL());
1210*8975f5c5SAndroid Build Coastguard WorkerGTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ImageTestMetal);
1211*8975f5c5SAndroid Build Coastguard WorkerGTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(ImageClearTestMetal);
1212*8975f5c5SAndroid Build Coastguard Worker}  // namespace angle
1213