| // | |
| // Copyright 2015 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // D3DTextureTest: | |
| // Tests of the EGL_ANGLE_d3d_texture_client_buffer extension | |
| #include "test_utils/ANGLETest.h" | |
| #include "test_utils/gl_raii.h" | |
| #include <d3d11.h> | |
| #include <windows.h> | |
| #include "util/EGLWindow.h" | |
| #include "util/com_utils.h" | |
| namespace angle | |
| { | |
| class D3DTextureTest : public ANGLETest | |
| { | |
| protected: | |
| D3DTextureTest() | |
| { | |
| setWindowWidth(128); | |
| setWindowHeight(128); | |
| setConfigRedBits(8); | |
| setConfigGreenBits(8); | |
| setConfigBlueBits(8); | |
| setConfigAlphaBits(8); | |
| setConfigDepthBits(24); | |
| setConfigStencilBits(8); | |
| } | |
| void testSetUp() override | |
| { | |
| constexpr char kVS[] = | |
| R"(precision highp float; | |
| attribute vec4 position; | |
| varying vec2 texcoord; | |
| void main() | |
| { | |
| gl_Position = position; | |
| texcoord = (position.xy * 0.5) + 0.5; | |
| texcoord.y = 1.0 - texcoord.y; | |
| })"; | |
| constexpr char kTextureFS[] = | |
| R"(precision highp float; | |
| uniform sampler2D tex; | |
| varying vec2 texcoord; | |
| void main() | |
| { | |
| gl_FragColor = texture2D(tex, texcoord); | |
| })"; | |
| constexpr char kTextureFSNoSampling[] = | |
| R"(precision highp float; | |
| void main() | |
| { | |
| gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0); | |
| })"; | |
| mTextureProgram = CompileProgram(kVS, kTextureFS); | |
| ASSERT_NE(0u, mTextureProgram) << "shader compilation failed."; | |
| mTextureUniformLocation = glGetUniformLocation(mTextureProgram, "tex"); | |
| ASSERT_NE(-1, mTextureUniformLocation); | |
| mTextureProgramNoSampling = CompileProgram(kVS, kTextureFSNoSampling); | |
| ASSERT_NE(0u, mTextureProgramNoSampling) << "shader compilation failed."; | |
| mD3D11Module = LoadLibrary(TEXT("d3d11.dll")); | |
| ASSERT_NE(nullptr, mD3D11Module); | |
| PFN_D3D11_CREATE_DEVICE createDeviceFunc = reinterpret_cast<PFN_D3D11_CREATE_DEVICE>( | |
| GetProcAddress(mD3D11Module, "D3D11CreateDevice")); | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| if (IsEGLDisplayExtensionEnabled(display, "EGL_EXT_device_query")) | |
| { | |
| PFNEGLQUERYDISPLAYATTRIBEXTPROC eglQueryDisplayAttribEXT = | |
| reinterpret_cast<PFNEGLQUERYDISPLAYATTRIBEXTPROC>( | |
| eglGetProcAddress("eglQueryDisplayAttribEXT")); | |
| PFNEGLQUERYDEVICEATTRIBEXTPROC eglQueryDeviceAttribEXT = | |
| reinterpret_cast<PFNEGLQUERYDEVICEATTRIBEXTPROC>( | |
| eglGetProcAddress("eglQueryDeviceAttribEXT")); | |
| EGLDeviceEXT device = 0; | |
| { | |
| EGLAttrib result = 0; | |
| EXPECT_EGL_TRUE(eglQueryDisplayAttribEXT(display, EGL_DEVICE_EXT, &result)); | |
| device = reinterpret_cast<EGLDeviceEXT>(result); | |
| } | |
| if (IsEGLDeviceExtensionEnabled(device, "EGL_ANGLE_device_d3d")) | |
| { | |
| EGLAttrib result = 0; | |
| if (eglQueryDeviceAttribEXT(device, EGL_D3D11_DEVICE_ANGLE, &result)) | |
| { | |
| mD3D11Device = reinterpret_cast<ID3D11Device *>(result); | |
| mD3D11Device->AddRef(); | |
| } | |
| else if (eglQueryDeviceAttribEXT(device, EGL_D3D9_DEVICE_ANGLE, &result)) | |
| { | |
| mD3D9Device = reinterpret_cast<IDirect3DDevice9 *>(result); | |
| mD3D9Device->AddRef(); | |
| } | |
| } | |
| } | |
| else | |
| { | |
| ASSERT_TRUE( | |
| SUCCEEDED(createDeviceFunc(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, nullptr, | |
| 0, D3D11_SDK_VERSION, &mD3D11Device, nullptr, nullptr))); | |
| } | |
| } | |
| void testTearDown() override | |
| { | |
| glDeleteProgram(mTextureProgram); | |
| if (mD3D11Device) | |
| { | |
| mD3D11Device->Release(); | |
| mD3D11Device = nullptr; | |
| } | |
| FreeLibrary(mD3D11Module); | |
| mD3D11Module = nullptr; | |
| if (mD3D9Device) | |
| { | |
| mD3D9Device->Release(); | |
| mD3D9Device = nullptr; | |
| } | |
| } | |
| EGLSurface createD3D11PBuffer(size_t width, | |
| size_t height, | |
| UINT sampleCount, | |
| UINT sampleQuality, | |
| UINT bindFlags, | |
| DXGI_FORMAT format, | |
| const EGLint *attribs) | |
| { | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| EGLConfig config = window->getConfig(); | |
| EXPECT_TRUE(mD3D11Device != nullptr); | |
| ID3D11Texture2D *texture = nullptr; | |
| CD3D11_TEXTURE2D_DESC desc(format, static_cast<UINT>(width), static_cast<UINT>(height), 1, | |
| 1, bindFlags); | |
| desc.SampleDesc.Count = sampleCount; | |
| desc.SampleDesc.Quality = sampleQuality; | |
| EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &texture))); | |
| EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE, | |
| texture, config, attribs); | |
| texture->Release(); | |
| return pbuffer; | |
| } | |
| EGLSurface createD3D11PBuffer(size_t width, | |
| size_t height, | |
| EGLint eglTextureFormat, | |
| EGLint eglTextureTarget, | |
| UINT sampleCount, | |
| UINT sampleQuality, | |
| UINT bindFlags, | |
| DXGI_FORMAT format) | |
| { | |
| EGLint attribs[] = { | |
| EGL_TEXTURE_FORMAT, eglTextureFormat, EGL_TEXTURE_TARGET, | |
| eglTextureTarget, EGL_NONE, EGL_NONE, | |
| }; | |
| return createD3D11PBuffer(width, height, sampleCount, sampleQuality, bindFlags, format, | |
| attribs); | |
| } | |
| EGLSurface createPBuffer(size_t width, | |
| size_t height, | |
| EGLint eglTextureFormat, | |
| EGLint eglTextureTarget, | |
| UINT sampleCount, | |
| UINT sampleQuality) | |
| { | |
| if (mD3D11Device) | |
| { | |
| return createD3D11PBuffer( | |
| width, height, eglTextureFormat, eglTextureTarget, sampleCount, sampleQuality, | |
| D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM); | |
| } | |
| if (mD3D9Device) | |
| { | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| EGLConfig config = window->getConfig(); | |
| EGLint attribs[] = { | |
| EGL_TEXTURE_FORMAT, eglTextureFormat, EGL_TEXTURE_TARGET, | |
| eglTextureTarget, EGL_NONE, EGL_NONE, | |
| }; | |
| // Multisampled textures are not supported on D3D9. | |
| EXPECT_TRUE(sampleCount <= 1); | |
| EXPECT_TRUE(sampleQuality == 0); | |
| IDirect3DTexture9 *texture = nullptr; | |
| EXPECT_TRUE(SUCCEEDED(mD3D9Device->CreateTexture( | |
| static_cast<UINT>(width), static_cast<UINT>(height), 1, D3DUSAGE_RENDERTARGET, | |
| D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &texture, nullptr))); | |
| EGLSurface pbuffer = eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE, | |
| texture, config, attribs); | |
| texture->Release(); | |
| return pbuffer; | |
| } | |
| else | |
| { | |
| return EGL_NO_SURFACE; | |
| } | |
| } | |
| bool valid() const | |
| { | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| if (!IsEGLDisplayExtensionEnabled(display, "EGL_ANGLE_d3d_texture_client_buffer")) | |
| { | |
| std::cout << "Test skipped due to missing EGL_ANGLE_d3d_texture_client_buffer" | |
| << std::endl; | |
| return false; | |
| } | |
| if (!mD3D11Device && !mD3D9Device) | |
| { | |
| std::cout << "Test skipped due to no D3D devices being available." << std::endl; | |
| return false; | |
| } | |
| if (IsWindows() && IsAMD() && IsOpenGL()) | |
| { | |
| std::cout << "Test skipped on Windows AMD OpenGL." << std::endl; | |
| return false; | |
| } | |
| if (IsWindows() && IsIntel() && IsOpenGL()) | |
| { | |
| std::cout << "Test skipped on Windows Intel OpenGL." << std::endl; | |
| return false; | |
| } | |
| return true; | |
| } | |
| void testTextureSamplesAs50PercentGreen(GLuint texture) | |
| { | |
| GLFramebuffer scratchFbo; | |
| glBindFramebuffer(GL_FRAMEBUFFER, scratchFbo); | |
| GLTexture scratchTexture; | |
| glBindTexture(GL_TEXTURE_2D, scratchTexture); | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 32, 32, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); | |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, scratchTexture, | |
| 0); | |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| glUseProgram(mTextureProgram); | |
| glUniform1i(mTextureUniformLocation, 0); | |
| glActiveTexture(GL_TEXTURE0); | |
| glBindTexture(GL_TEXTURE_2D, texture); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| drawQuad(mTextureProgram, "position", 0.5f); | |
| ASSERT_GL_NO_ERROR(); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 127u, 0u, 255u), 2); | |
| } | |
| GLuint mTextureProgram; | |
| GLuint mTextureProgramNoSampling; | |
| GLint mTextureUniformLocation; | |
| HMODULE mD3D11Module = nullptr; | |
| ID3D11Device *mD3D11Device = nullptr; | |
| IDirect3DDevice9 *mD3D9Device = nullptr; | |
| }; | |
| // Test creating pbuffer from textures with several different DXGI formats. | |
| TEST_P(D3DTextureTest, TestD3D11SupportedFormatsSurface) | |
| { | |
| bool srgbSupported = IsGLExtensionEnabled("GL_EXT_sRGB") || getClientMajorVersion() == 3; | |
| ANGLE_SKIP_TEST_IF(!valid() || !mD3D11Device || !srgbSupported); | |
| const DXGI_FORMAT formats[] = {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, | |
| DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB}; | |
| for (size_t i = 0; i < 4; ++i) | |
| { | |
| if (formats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) | |
| { | |
| if (IsOpenGL()) | |
| { | |
| // This generates an invalid format error when calling wglDXRegisterObjectNV(). | |
| // Reproducible at least on NVIDIA driver 390.65 on Windows 10. | |
| std::cout << "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB subtest skipped: IsOpenGL().\n"; | |
| continue; | |
| } | |
| } | |
| EGLSurface pbuffer = createD3D11PBuffer(32, 32, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D, 1, 0, | |
| D3D11_BIND_RENDER_TARGET, formats[i]); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(EGL_NO_SURFACE, pbuffer); | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| EGLint colorspace = EGL_NONE; | |
| eglQuerySurface(display, pbuffer, EGL_GL_COLORSPACE, &colorspace); | |
| if (formats[i] == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB || | |
| formats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) | |
| { | |
| EXPECT_EQ(EGL_GL_COLORSPACE_SRGB, colorspace); | |
| } | |
| else | |
| { | |
| EXPECT_EQ(EGL_GL_COLORSPACE_LINEAR, colorspace); | |
| } | |
| eglMakeCurrent(display, pbuffer, pbuffer, window->getContext()); | |
| ASSERT_EGL_SUCCESS(); | |
| window->makeCurrent(); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| } | |
| // Test binding a pbuffer created from a D3D texture as a texture image with several different DXGI | |
| // formats. The test renders to and samples from the pbuffer. | |
| TEST_P(D3DTextureTest, TestD3D11SupportedFormatsTexture) | |
| { | |
| bool srgb8alpha8TextureAttachmentSupported = getClientMajorVersion() >= 3; | |
| ANGLE_SKIP_TEST_IF(!valid() || !mD3D11Device || !srgb8alpha8TextureAttachmentSupported); | |
| bool srgbWriteControlSupported = | |
| IsGLExtensionEnabled("GL_EXT_sRGB_write_control") && !IsOpenGL(); | |
| const DXGI_FORMAT formats[] = {DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_B8G8R8A8_UNORM, | |
| DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, | |
| DXGI_FORMAT_B8G8R8A8_UNORM_SRGB}; | |
| for (size_t i = 0; i < 4; ++i) | |
| { | |
| if (formats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) | |
| { | |
| if (IsOpenGL()) | |
| { | |
| // This generates an invalid format error when calling wglDXRegisterObjectNV(). | |
| // Reproducible at least on NVIDIA driver 390.65 on Windows 10. | |
| std::cout << "DXGI_FORMAT_B8G8R8A8_UNORM_SRGB subtest skipped: IsOpenGL().\n"; | |
| continue; | |
| } | |
| } | |
| SCOPED_TRACE(std::string("Test case:") + std::to_string(i)); | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| EGLSurface pbuffer = | |
| createD3D11PBuffer(32, 32, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D, 1, 0, | |
| D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, formats[i]); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(EGL_NO_SURFACE, pbuffer); | |
| EGLint colorspace = EGL_NONE; | |
| eglQuerySurface(display, pbuffer, EGL_GL_COLORSPACE, &colorspace); | |
| GLuint texture = 0u; | |
| glGenTextures(1, &texture); | |
| glBindTexture(GL_TEXTURE_2D, texture); | |
| EGLBoolean result = eglBindTexImage(display, pbuffer, EGL_BACK_BUFFER); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_EGL_TRUE(result); | |
| GLuint fbo = 0u; | |
| glGenFramebuffers(1, &fbo); | |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); | |
| glViewport(0, 0, 32, 32); | |
| GLint colorEncoding = 0; | |
| glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
| GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT, | |
| &colorEncoding); | |
| if (formats[i] == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB || | |
| formats[i] == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB) | |
| { | |
| EXPECT_EQ(EGL_GL_COLORSPACE_SRGB, colorspace); | |
| EXPECT_EQ(GL_SRGB_EXT, colorEncoding); | |
| } | |
| else | |
| { | |
| EXPECT_EQ(EGL_GL_COLORSPACE_LINEAR, colorspace); | |
| EXPECT_EQ(GL_LINEAR, colorEncoding); | |
| } | |
| // Clear the texture with 50% green and check that the color value written is correct. | |
| glClearColor(0.0f, 0.5f, 0.0f, 1.0f); | |
| if (colorEncoding == GL_SRGB_EXT) | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 188u, 0u, 255u), 2); | |
| // Disable SRGB and run the non-sRGB test case. | |
| if (srgbWriteControlSupported) | |
| glDisable(GL_FRAMEBUFFER_SRGB_EXT); | |
| } | |
| if (colorEncoding == GL_LINEAR || srgbWriteControlSupported) | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 127u, 0u, 255u), 2); | |
| } | |
| // Draw with the texture to a linear framebuffer and check that the color value written is | |
| // correct. | |
| testTextureSamplesAs50PercentGreen(texture); | |
| glBindFramebuffer(GL_FRAMEBUFFER, 0u); | |
| glBindTexture(GL_TEXTURE_2D, 0u); | |
| glDeleteTextures(1, &texture); | |
| glDeleteFramebuffers(1, &fbo); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| } | |
| // Test binding a pbuffer created from a D3D texture as a texture image with typeless texture | |
| // formats. | |
| TEST_P(D3DTextureTest, TestD3D11TypelessTexture) | |
| { | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| ANGLE_SKIP_TEST_IF(!valid()); | |
| // Typeless formats are optional in the spec and currently only supported on D3D11 backend. | |
| ANGLE_SKIP_TEST_IF(!IsD3D11()); | |
| // GL_SRGB8_ALPHA8 texture attachment support is required. | |
| ANGLE_SKIP_TEST_IF(getClientMajorVersion() < 3); | |
| const std::array<EGLint, 2> eglGlColorspaces = {EGL_GL_COLORSPACE_LINEAR, | |
| EGL_GL_COLORSPACE_SRGB}; | |
| const std::array<DXGI_FORMAT, 2> dxgiFormats = {DXGI_FORMAT_R8G8B8A8_TYPELESS, | |
| DXGI_FORMAT_B8G8R8A8_TYPELESS}; | |
| for (auto eglGlColorspace : eglGlColorspaces) | |
| { | |
| for (auto dxgiFormat : dxgiFormats) | |
| { | |
| SCOPED_TRACE(std::string("Test case:") + std::to_string(eglGlColorspace) + " / " + | |
| std::to_string(dxgiFormat)); | |
| EGLint attribs[] = { | |
| EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, | |
| EGL_GL_COLORSPACE, eglGlColorspace, EGL_NONE, EGL_NONE, | |
| }; | |
| EGLSurface pbuffer = createD3D11PBuffer( | |
| 32, 32, 1, 0, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, dxgiFormat, | |
| attribs); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(EGL_NO_SURFACE, pbuffer); | |
| EGLint colorspace = EGL_NONE; | |
| eglQuerySurface(display, pbuffer, EGL_GL_COLORSPACE, &colorspace); | |
| GLuint texture = 0u; | |
| glGenTextures(1, &texture); | |
| glBindTexture(GL_TEXTURE_2D, texture); | |
| EGLBoolean result = eglBindTexImage(display, pbuffer, EGL_BACK_BUFFER); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_EGL_TRUE(result); | |
| GLuint fbo = 0u; | |
| glGenFramebuffers(1, &fbo); | |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); | |
| glViewport(0, 0, 32, 32); | |
| GLint colorEncoding = 0; | |
| glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
| GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT, | |
| &colorEncoding); | |
| if (eglGlColorspace == EGL_GL_COLORSPACE_LINEAR) | |
| { | |
| EXPECT_EQ(EGL_GL_COLORSPACE_LINEAR, colorspace); | |
| EXPECT_EQ(GL_LINEAR, colorEncoding); | |
| } | |
| else | |
| { | |
| EXPECT_EQ(EGL_GL_COLORSPACE_SRGB, colorspace); | |
| EXPECT_EQ(GL_SRGB_EXT, colorEncoding); | |
| } | |
| // Clear the texture with 50% green and check that the color value written is correct. | |
| glClearColor(0.0f, 0.5f, 0.0f, 1.0f); | |
| if (colorEncoding == GL_SRGB_EXT) | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 188u, 0u, 255u), 2); | |
| } | |
| if (colorEncoding == GL_LINEAR) | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 127u, 0u, 255u), 2); | |
| } | |
| // Draw with the texture to a linear framebuffer and check that the color value written | |
| // is correct. | |
| testTextureSamplesAs50PercentGreen(texture); | |
| glBindFramebuffer(GL_FRAMEBUFFER, 0u); | |
| glBindTexture(GL_TEXTURE_2D, 0u); | |
| glDeleteTextures(1, &texture); | |
| glDeleteFramebuffers(1, &fbo); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| } | |
| } | |
| class D3DTextureTestES3 : public D3DTextureTest | |
| { | |
| protected: | |
| D3DTextureTestES3() : D3DTextureTest() {} | |
| }; | |
| // Test swizzling a pbuffer created from a D3D texture as a texture image with typeless texture | |
| // formats. | |
| TEST_P(D3DTextureTestES3, TestD3D11TypelessTextureSwizzle) | |
| { | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| ANGLE_SKIP_TEST_IF(!valid()); | |
| // Typeless formats are optional in the spec and currently only supported on D3D11 backend. | |
| ANGLE_SKIP_TEST_IF(!IsD3D11()); | |
| const std::array<EGLint, 2> eglGlColorspaces = {EGL_GL_COLORSPACE_LINEAR, | |
| EGL_GL_COLORSPACE_SRGB}; | |
| const std::array<DXGI_FORMAT, 2> dxgiFormats = {DXGI_FORMAT_R8G8B8A8_TYPELESS, | |
| DXGI_FORMAT_B8G8R8A8_TYPELESS}; | |
| for (auto eglGlColorspace : eglGlColorspaces) | |
| { | |
| for (auto dxgiFormat : dxgiFormats) | |
| { | |
| SCOPED_TRACE(std::string("Test case:") + std::to_string(eglGlColorspace) + " / " + | |
| std::to_string(dxgiFormat)); | |
| EGLint attribs[] = { | |
| EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, | |
| EGL_GL_COLORSPACE, eglGlColorspace, EGL_NONE, EGL_NONE, | |
| }; | |
| EGLSurface pbuffer = createD3D11PBuffer( | |
| 32, 32, 1, 0, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, dxgiFormat, | |
| attribs); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(EGL_NO_SURFACE, pbuffer); | |
| EGLint colorspace = EGL_NONE; | |
| eglQuerySurface(display, pbuffer, EGL_GL_COLORSPACE, &colorspace); | |
| GLuint texture = 0u; | |
| glGenTextures(1, &texture); | |
| glBindTexture(GL_TEXTURE_2D, texture); | |
| EGLBoolean result = eglBindTexImage(display, pbuffer, EGL_BACK_BUFFER); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_EGL_TRUE(result); | |
| GLuint fbo = 0u; | |
| glGenFramebuffers(1, &fbo); | |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); | |
| glViewport(0, 0, 32, 32); | |
| GLint colorEncoding = 0; | |
| glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
| GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT, | |
| &colorEncoding); | |
| // Clear the texture with 50% blue and check that the color value written is correct. | |
| glClearColor(0.0f, 0.0f, 0.5f, 1.0f); | |
| if (colorEncoding == GL_SRGB_EXT) | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 0u, 188u, 255u), 2); | |
| } | |
| if (colorEncoding == GL_LINEAR) | |
| { | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| EXPECT_PIXEL_COLOR_NEAR(0, 0, GLColor(0u, 0u, 127u, 255u), 2); | |
| } | |
| // Swizzle the green channel to be sampled from the blue channel of the texture and vice | |
| // versa. | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_BLUE); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_GREEN); | |
| ASSERT_GL_NO_ERROR(); | |
| // Draw with the texture to a linear framebuffer and check that the color value written | |
| // is correct. | |
| testTextureSamplesAs50PercentGreen(texture); | |
| glBindFramebuffer(GL_FRAMEBUFFER, 0u); | |
| glBindTexture(GL_TEXTURE_2D, 0u); | |
| glDeleteTextures(1, &texture); | |
| glDeleteFramebuffers(1, &fbo); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| } | |
| } | |
| // Test that EGL_GL_COLORSPACE attrib is not allowed for typed D3D textures. | |
| TEST_P(D3DTextureTest, GlColorspaceNotAllowedForTypedD3DTexture) | |
| { | |
| ANGLE_SKIP_TEST_IF(!valid()); | |
| // D3D11 device is required to be able to create the texture. | |
| ANGLE_SKIP_TEST_IF(!mD3D11Device); | |
| // SRGB support is required. | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3); | |
| EGLint attribsExplicitColorspace[] = { | |
| EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, | |
| EGL_GL_COLORSPACE, EGL_GL_COLORSPACE_SRGB, EGL_NONE, EGL_NONE, | |
| }; | |
| EGLSurface pbuffer = | |
| createD3D11PBuffer(32, 32, 1, 0, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, | |
| DXGI_FORMAT_R8G8B8A8_UNORM, attribsExplicitColorspace); | |
| ASSERT_EGL_ERROR(EGL_BAD_MATCH); | |
| ASSERT_EQ(EGL_NO_SURFACE, pbuffer); | |
| } | |
| // Test that trying to create a pbuffer from a typeless texture fails as expected on the backends | |
| // where they are known not to be supported. | |
| TEST_P(D3DTextureTest, TypelessD3DTextureNotSupported) | |
| { | |
| ANGLE_SKIP_TEST_IF(!valid()); | |
| // D3D11 device is required to be able to create the texture. | |
| ANGLE_SKIP_TEST_IF(!mD3D11Device); | |
| // Currently typeless textures are supported on the D3D11 backend. We're testing the backends | |
| // where there is no support. | |
| ANGLE_SKIP_TEST_IF(IsD3D11()); | |
| // SRGB support is required. | |
| ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_EXT_sRGB") && getClientMajorVersion() < 3); | |
| EGLint attribs[] = { | |
| EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, EGL_TEXTURE_TARGET, | |
| EGL_TEXTURE_2D, EGL_NONE, EGL_NONE, | |
| }; | |
| EGLSurface pbuffer = | |
| createD3D11PBuffer(32, 32, 1, 0, D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE, | |
| DXGI_FORMAT_R8G8B8A8_TYPELESS, attribs); | |
| ASSERT_EGL_ERROR(EGL_BAD_PARAMETER); | |
| ASSERT_EQ(EGL_NO_SURFACE, pbuffer); | |
| } | |
| // Test creating a pbuffer with unnecessary EGL_WIDTH and EGL_HEIGHT attributes because that's what | |
| // Chromium does. This is a regression test for crbug.com/794086 | |
| TEST_P(D3DTextureTest, UnnecessaryWidthHeightAttributes) | |
| { | |
| ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11()); | |
| ASSERT_TRUE(mD3D11Device != nullptr); | |
| ID3D11Texture2D *texture = nullptr; | |
| CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, 1, 1, 1, 1, D3D11_BIND_RENDER_TARGET); | |
| desc.SampleDesc.Count = 1; | |
| desc.SampleDesc.Quality = 0; | |
| EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &texture))); | |
| EGLint attribs[] = { | |
| EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA, | |
| EGL_TEXTURE_TARGET, EGL_TEXTURE_2D, | |
| EGL_WIDTH, 1, | |
| EGL_HEIGHT, 1, | |
| EGL_NONE, EGL_NONE, | |
| }; | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| EGLConfig config = window->getConfig(); | |
| EGLSurface pbuffer = | |
| eglCreatePbufferFromClientBuffer(display, EGL_D3D_TEXTURE_ANGLE, texture, config, attribs); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(pbuffer, EGL_NO_SURFACE); | |
| texture->Release(); | |
| // Make current with fixture EGL to ensure the Surface can be released immediately. | |
| getEGLWindow()->makeCurrent(); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| // Test creating a pbuffer from a d3d surface and clearing it | |
| TEST_P(D3DTextureTest, Clear) | |
| { | |
| if (!valid()) | |
| { | |
| return; | |
| } | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| const size_t bufferSize = 32; | |
| EGLSurface pbuffer = | |
| createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 1, 0); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(pbuffer, EGL_NO_SURFACE); | |
| // Apply the Pbuffer and clear it to purple and verify | |
| eglMakeCurrent(display, pbuffer, pbuffer, window->getContext()); | |
| ASSERT_EGL_SUCCESS(); | |
| glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); | |
| glClearColor(1.0f, 0.0f, 1.0f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0, | |
| 255, 255); | |
| // Make current with fixture EGL to ensure the Surface can be released immediately. | |
| getEGLWindow()->makeCurrent(); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| // Test creating a pbuffer with a D3D texture and depth stencil bits in the EGL config creates keeps | |
| // its depth stencil buffer | |
| TEST_P(D3DTextureTest, DepthStencil) | |
| { | |
| if (!valid()) | |
| { | |
| return; | |
| } | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| const size_t bufferSize = 32; | |
| EGLSurface pbuffer = | |
| createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 1, 0); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(pbuffer, EGL_NO_SURFACE); | |
| // Apply the Pbuffer and clear it to purple and verify | |
| eglMakeCurrent(display, pbuffer, pbuffer, window->getContext()); | |
| ASSERT_EGL_SUCCESS(); | |
| glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); | |
| glClearColor(0.0f, 1.0f, 1.0f, 1.0f); | |
| glClearDepthf(0.5f); | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| glEnable(GL_DEPTH_TEST); | |
| glDepthMask(GL_FALSE); | |
| glUseProgram(mTextureProgram); | |
| glUniform1i(mTextureUniformLocation, 0); | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); | |
| // Draw a quad that will fail the depth test and verify that the buffer is unchanged | |
| drawQuad(mTextureProgram, "position", 1.0f); | |
| EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, | |
| GLColor::cyan); | |
| // Draw a quad that will pass the depth test and verify that the buffer is green | |
| drawQuad(mTextureProgram, "position", -1.0f); | |
| EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, | |
| GLColor::green); | |
| // Make current with fixture EGL to ensure the Surface can be released immediately. | |
| getEGLWindow()->makeCurrent(); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| // Test creating a pbuffer from a d3d surface and binding it to a texture | |
| TEST_P(D3DTextureTest, BindTexImage) | |
| { | |
| if (!valid()) | |
| { | |
| return; | |
| } | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| const size_t bufferSize = 32; | |
| EGLSurface pbuffer = | |
| createPBuffer(bufferSize, bufferSize, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D, 1, 0); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(pbuffer, EGL_NO_SURFACE); | |
| // Apply the Pbuffer and clear it to purple | |
| eglMakeCurrent(display, pbuffer, pbuffer, window->getContext()); | |
| ASSERT_EGL_SUCCESS(); | |
| glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); | |
| glClearColor(1.0f, 0.0f, 1.0f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0, | |
| 255, 255); | |
| // Apply the window surface | |
| eglMakeCurrent(display, window->getSurface(), window->getSurface(), window->getContext()); | |
| // Create a texture and bind the Pbuffer to it | |
| GLuint texture = 0; | |
| glGenTextures(1, &texture); | |
| glBindTexture(GL_TEXTURE_2D, texture); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| EXPECT_GL_NO_ERROR(); | |
| eglBindTexImage(display, pbuffer, EGL_BACK_BUFFER); | |
| glViewport(0, 0, getWindowWidth(), getWindowHeight()); | |
| ASSERT_EGL_SUCCESS(); | |
| // Draw a quad and verify that it is purple | |
| glUseProgram(mTextureProgram); | |
| glUniform1i(mTextureUniformLocation, 0); | |
| drawQuad(mTextureProgram, "position", 0.5f); | |
| EXPECT_GL_NO_ERROR(); | |
| // Unbind the texture | |
| eglReleaseTexImage(display, pbuffer, EGL_BACK_BUFFER); | |
| ASSERT_EGL_SUCCESS(); | |
| // Verify that purple was drawn | |
| EXPECT_PIXEL_EQ(getWindowWidth() / 2, getWindowHeight() / 2, 255, 0, 255, 255); | |
| glDeleteTextures(1, &texture); | |
| // Make current with fixture EGL to ensure the Surface can be released immediately. | |
| getEGLWindow()->makeCurrent(); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| // Verify that creating a pbuffer with a multisampled texture will fail on a non-multisampled | |
| // window. | |
| TEST_P(D3DTextureTest, CheckSampleMismatch) | |
| { | |
| if (!valid()) | |
| { | |
| return; | |
| } | |
| // Multisampling is not supported on D3D9 or OpenGL. | |
| ANGLE_SKIP_TEST_IF(IsD3D9() || IsOpenGL()); | |
| constexpr size_t bufferSize = 32; | |
| EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 2, | |
| static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN)); | |
| EXPECT_EGL_ERROR(EGL_BAD_PARAMETER); | |
| EXPECT_EQ(pbuffer, nullptr); | |
| } | |
| // Tests what happens when we make a PBuffer that isn't shader-readable. | |
| TEST_P(D3DTextureTest, NonReadablePBuffer) | |
| { | |
| ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11()); | |
| constexpr size_t bufferSize = 32; | |
| EGLSurface pbuffer = | |
| createD3D11PBuffer(bufferSize, bufferSize, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D, 1, 0, | |
| D3D11_BIND_RENDER_TARGET, DXGI_FORMAT_R8G8B8A8_UNORM); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(pbuffer, EGL_NO_SURFACE); | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| eglMakeCurrent(display, pbuffer, pbuffer, window->getContext()); | |
| ASSERT_EGL_SUCCESS(); | |
| glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); | |
| // Clear to green. | |
| glClearColor(0.0f, 1.0f, 0.0f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); | |
| // Copy the green color to a texture. | |
| GLTexture tex; | |
| glBindTexture(GL_TEXTURE_2D, tex); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, bufferSize, bufferSize, 0); | |
| ASSERT_GL_NO_ERROR(); | |
| // Clear to red. | |
| glClearColor(1.0f, 0.0f, 0.0f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::red); | |
| // Draw with the texture and expect green. | |
| draw2DTexturedQuad(0.5f, 1.0f, false); | |
| EXPECT_PIXEL_COLOR_EQ(0, 0, GLColor::green); | |
| // Make current with fixture EGL to ensure the Surface can be released immediately. | |
| getEGLWindow()->makeCurrent(); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| class D3DTextureTestMS : public D3DTextureTest | |
| { | |
| protected: | |
| D3DTextureTestMS() : D3DTextureTest() | |
| { | |
| setSamples(4); | |
| setMultisampleEnabled(true); | |
| } | |
| }; | |
| // Test creating a pbuffer from a multisampled d3d surface and clearing it. | |
| TEST_P(D3DTextureTestMS, Clear) | |
| { | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| constexpr size_t bufferSize = 32; | |
| constexpr UINT testpoint = bufferSize / 2; | |
| EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 4, | |
| static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN)); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(pbuffer, EGL_NO_SURFACE); | |
| // Apply the Pbuffer and clear it to magenta and verify | |
| eglMakeCurrent(display, pbuffer, pbuffer, window->getContext()); | |
| ASSERT_EGL_SUCCESS(); | |
| glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); | |
| glClearColor(1.0f, 0.0f, 1.0f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| EXPECT_PIXEL_COLOR_EQ(testpoint, testpoint, GLColor::magenta); | |
| // Make current with fixture EGL to ensure the Surface can be released immediately. | |
| getEGLWindow()->makeCurrent(); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| // Test creating a pbuffer from a multisampled d3d surface and drawing with a program. | |
| TEST_P(D3DTextureTestMS, DrawProgram) | |
| { | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| constexpr size_t bufferSize = 32; | |
| EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 4, | |
| static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN)); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(pbuffer, EGL_NO_SURFACE); | |
| // Apply the Pbuffer and clear it to magenta | |
| eglMakeCurrent(display, pbuffer, pbuffer, window->getContext()); | |
| ASSERT_EGL_SUCCESS(); | |
| glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); | |
| glClearColor(1.0f, 0.0f, 1.0f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| constexpr GLint testPoint = bufferSize / 2; | |
| EXPECT_PIXEL_COLOR_EQ(testPoint, testPoint, GLColor::magenta); | |
| // Apply the window surface | |
| eglMakeCurrent(display, window->getSurface(), window->getSurface(), window->getContext()); | |
| ASSERT_EGL_SUCCESS(); | |
| glViewport(0, 0, getWindowWidth(), getWindowHeight()); | |
| ASSERT_EGL_SUCCESS(); | |
| // Draw a quad and verify that it is magenta | |
| glUseProgram(mTextureProgramNoSampling); | |
| EXPECT_GL_NO_ERROR(); | |
| drawQuad(mTextureProgramNoSampling, "position", 0.5f); | |
| EXPECT_GL_NO_ERROR(); | |
| // Verify that magenta was drawn | |
| EXPECT_PIXEL_COLOR_EQ(getWindowWidth() / 2, getWindowHeight() / 2, GLColor::magenta); | |
| // Make current with fixture EGL to ensure the Surface can be released immediately. | |
| getEGLWindow()->makeCurrent(); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| // Test for failure when creating a pbuffer from a multisampled d3d surface to bind to a texture. | |
| TEST_P(D3DTextureTestMS, BindTexture) | |
| { | |
| constexpr size_t bufferSize = 32; | |
| EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_TEXTURE_RGBA, EGL_TEXTURE_2D, 4, | |
| static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN)); | |
| EXPECT_EGL_ERROR(EGL_BAD_ATTRIBUTE); | |
| EXPECT_EQ(pbuffer, nullptr); | |
| } | |
| // Verify that creating a pbuffer from a multisampled texture with a multisampled window will fail | |
| // when the sample counts do not match. | |
| TEST_P(D3DTextureTestMS, CheckSampleMismatch) | |
| { | |
| constexpr size_t bufferSize = 32; | |
| EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 2, | |
| static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN)); | |
| EXPECT_EGL_ERROR(EGL_BAD_PARAMETER); | |
| EXPECT_EQ(pbuffer, nullptr); | |
| } | |
| // Test creating a pbuffer with a D3D texture and depth stencil bits in the EGL config creates keeps | |
| // its depth stencil buffer | |
| TEST_P(D3DTextureTestMS, DepthStencil) | |
| { | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| const size_t bufferSize = 32; | |
| EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 4, | |
| static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN)); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(EGL_NO_SURFACE, pbuffer); | |
| // Apply the Pbuffer and clear it to purple and verify | |
| eglMakeCurrent(display, pbuffer, pbuffer, window->getContext()); | |
| ASSERT_EGL_SUCCESS(); | |
| glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); | |
| glClearColor(0.0f, 1.0f, 1.0f, 1.0f); | |
| glClearDepthf(0.5f); | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| glEnable(GL_DEPTH_TEST); | |
| glDepthMask(GL_FALSE); | |
| glUseProgram(mTextureProgram); | |
| glUniform1i(mTextureUniformLocation, 0); | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); | |
| // Draw a quad that will fail the depth test and verify that the buffer is unchanged | |
| drawQuad(mTextureProgram, "position", 1.0f); | |
| EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, | |
| GLColor::cyan); | |
| // Draw a quad that will pass the depth test and verify that the buffer is green | |
| drawQuad(mTextureProgram, "position", -1.0f); | |
| EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, | |
| GLColor::green); | |
| // Make current with fixture EGL to ensure the Surface can be released immediately. | |
| getEGLWindow()->makeCurrent(); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| // Test copyTexImage2D with a multisampled resource | |
| TEST_P(D3DTextureTestMS, CopyTexImage2DTest) | |
| { | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| constexpr size_t bufferSize = 32; | |
| EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 4, | |
| static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN)); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(EGL_NO_SURFACE, pbuffer); | |
| // Apply the Pbuffer and clear it to magenta and verify | |
| eglMakeCurrent(display, pbuffer, pbuffer, window->getContext()); | |
| ASSERT_EGL_SUCCESS(); | |
| glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); | |
| glClearColor(1.0f, 0.0f, 1.0f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| glUseProgram(mTextureProgram); | |
| glUniform1i(mTextureUniformLocation, 0); | |
| // Specify a 2D texture and set it to green | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); | |
| // Copy from the multisampled framebuffer to the 2D texture | |
| glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0); | |
| // Draw a quad and verify the color is magenta, not green | |
| drawQuad(mTextureProgram, "position", 1.0f); | |
| EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, | |
| GLColor::magenta); | |
| ASSERT_GL_NO_ERROR(); | |
| // Make current with fixture EGL to ensure the Surface can be released immediately. | |
| getEGLWindow()->makeCurrent(); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| // Test copyTexSubImage2D with a multisampled resource | |
| TEST_P(D3DTextureTestMS, CopyTexSubImage2DTest) | |
| { | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| constexpr size_t bufferSize = 32; | |
| EGLSurface pbuffer = createPBuffer(bufferSize, bufferSize, EGL_NO_TEXTURE, EGL_NO_TEXTURE, 4, | |
| static_cast<UINT>(D3D11_STANDARD_MULTISAMPLE_PATTERN)); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(EGL_NO_SURFACE, pbuffer); | |
| // Apply the Pbuffer and clear it to magenta and verify | |
| eglMakeCurrent(display, pbuffer, pbuffer, window->getContext()); | |
| ASSERT_EGL_SUCCESS(); | |
| glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); | |
| glClearColor(1.0f, 0.0f, 1.0f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| glUseProgram(mTextureProgram); | |
| glUniform1i(mTextureUniformLocation, 0); | |
| // Specify a 2D texture and set it to green | |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &GLColor::green); | |
| // Copy from the multisampled framebuffer to the 2D texture | |
| glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1); | |
| // Draw a quad and verify the color is magenta, not green | |
| drawQuad(mTextureProgram, "position", 1.0f); | |
| EXPECT_PIXEL_COLOR_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, | |
| GLColor::magenta); | |
| ASSERT_GL_NO_ERROR(); | |
| // Make current with fixture EGL to ensure the Surface can be released immediately. | |
| getEGLWindow()->makeCurrent(); | |
| eglDestroySurface(display, pbuffer); | |
| } | |
| TEST_P(D3DTextureTest, ClearTextureImage) | |
| { | |
| ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11()); | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| window->makeCurrent(); | |
| const UINT bufferSize = 32; | |
| EXPECT_TRUE(mD3D11Device != nullptr); | |
| ID3D11Texture2D *d3d11_texture = nullptr; | |
| CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, bufferSize, bufferSize, 1, 1, | |
| D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); | |
| EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11_texture))); | |
| const EGLint attribs[] = {EGL_NONE}; | |
| EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE, | |
| static_cast<EGLClientBuffer>(d3d11_texture), attribs); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(image, EGL_NO_IMAGE_KHR); | |
| GLuint texture; | |
| glGenTextures(1, &texture); | |
| glBindTexture(GL_TEXTURE_2D, texture); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| ASSERT_GL_NO_ERROR(); | |
| glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); | |
| ASSERT_GL_NO_ERROR(); | |
| GLuint fbo; | |
| glGenFramebuffers(1, &fbo); | |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); | |
| EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), | |
| static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE)); | |
| ASSERT_GL_NO_ERROR(); | |
| glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); | |
| glClearColor(1.0f, 0.0f, 1.0f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0, | |
| 255, 255); | |
| glDeleteFramebuffers(1, &fbo); | |
| glDeleteTextures(1, &texture); | |
| d3d11_texture->Release(); | |
| } | |
| TEST_P(D3DTextureTest, NonRenderableTextureImage) | |
| { | |
| ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11()); | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| window->makeCurrent(); | |
| const UINT bufferSize = 32; | |
| EXPECT_TRUE(mD3D11Device != nullptr); | |
| ID3D11Texture2D *d3d11_texture = nullptr; | |
| CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, bufferSize, bufferSize, 1, 1, | |
| D3D11_BIND_SHADER_RESOURCE); | |
| EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11_texture))); | |
| const EGLint attribs[] = {EGL_NONE}; | |
| EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE, | |
| static_cast<EGLClientBuffer>(d3d11_texture), attribs); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(image, EGL_NO_IMAGE_KHR); | |
| GLuint texture; | |
| glGenTextures(1, &texture); | |
| glBindTexture(GL_TEXTURE_2D, texture); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| ASSERT_GL_NO_ERROR(); | |
| glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); | |
| ASSERT_GL_NO_ERROR(); | |
| GLuint fbo; | |
| glGenFramebuffers(1, &fbo); | |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); | |
| EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), | |
| static_cast<unsigned>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)); | |
| ASSERT_GL_NO_ERROR(); | |
| glDeleteFramebuffers(1, &fbo); | |
| glDeleteTextures(1, &texture); | |
| d3d11_texture->Release(); | |
| } | |
| TEST_P(D3DTextureTest, RGBEmulationTextureImage) | |
| { | |
| ANGLE_SKIP_TEST_IF(!valid() || !IsD3D11()); | |
| EGLWindow *window = getEGLWindow(); | |
| EGLDisplay display = window->getDisplay(); | |
| window->makeCurrent(); | |
| const UINT bufferSize = 32; | |
| EXPECT_TRUE(mD3D11Device != nullptr); | |
| ID3D11Texture2D *d3d11_texture = nullptr; | |
| CD3D11_TEXTURE2D_DESC desc(DXGI_FORMAT_R8G8B8A8_UNORM, bufferSize, bufferSize, 1, 1, | |
| D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET); | |
| EXPECT_TRUE(SUCCEEDED(mD3D11Device->CreateTexture2D(&desc, nullptr, &d3d11_texture))); | |
| const EGLint attribs[] = {EGL_TEXTURE_INTERNAL_FORMAT_ANGLE, GL_RGB, EGL_NONE}; | |
| EGLImage image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_D3D11_TEXTURE_ANGLE, | |
| static_cast<EGLClientBuffer>(d3d11_texture), attribs); | |
| ASSERT_EGL_SUCCESS(); | |
| ASSERT_NE(image, EGL_NO_IMAGE_KHR); | |
| GLuint texture; | |
| glGenTextures(1, &texture); | |
| glBindTexture(GL_TEXTURE_2D, texture); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
| ASSERT_GL_NO_ERROR(); | |
| glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image); | |
| ASSERT_GL_NO_ERROR(); | |
| GLuint fbo; | |
| glGenFramebuffers(1, &fbo); | |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
| glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0); | |
| EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), | |
| static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE)); | |
| ASSERT_GL_NO_ERROR(); | |
| // Although we are writing 0.5 to the alpha channel it should have the same | |
| // side effects as if alpha were 1.0. | |
| glViewport(0, 0, static_cast<GLsizei>(bufferSize), static_cast<GLsizei>(bufferSize)); | |
| glClearColor(1.0f, 0.0f, 1.0f, 0.5f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0, | |
| 255, 255); | |
| GLuint rgbaRbo; | |
| glGenRenderbuffers(1, &rgbaRbo); | |
| glBindRenderbuffer(GL_RENDERBUFFER, rgbaRbo); | |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, bufferSize, bufferSize); | |
| GLuint rgbaFbo; | |
| glGenFramebuffers(1, &rgbaFbo); | |
| glBindFramebuffer(GL_FRAMEBUFFER, rgbaFbo); | |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rgbaRbo); | |
| EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), | |
| static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE)); | |
| ASSERT_GL_NO_ERROR(); | |
| // BlitFramebuffer from/to RGBA framebuffer fails. | |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, rgbaFbo); | |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); | |
| glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize, | |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); | |
| ASSERT_GL_ERROR(GL_INVALID_OPERATION); | |
| ASSERT_GL_NO_ERROR(); | |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); | |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rgbaFbo); | |
| glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize, | |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); | |
| ASSERT_GL_ERROR(GL_INVALID_OPERATION); | |
| ASSERT_GL_NO_ERROR(); | |
| GLuint rgbRbo; | |
| glGenRenderbuffers(1, &rgbRbo); | |
| glBindRenderbuffer(GL_RENDERBUFFER, rgbRbo); | |
| glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB8_OES, bufferSize, bufferSize); | |
| GLuint rgbFbo; | |
| glGenFramebuffers(1, &rgbFbo); | |
| glBindFramebuffer(GL_FRAMEBUFFER, rgbFbo); | |
| glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rgbRbo); | |
| EXPECT_EQ(glCheckFramebufferStatus(GL_FRAMEBUFFER), | |
| static_cast<unsigned>(GL_FRAMEBUFFER_COMPLETE)); | |
| ASSERT_GL_NO_ERROR(); | |
| glClearColor(1.0f, 0.0f, 1.0f, 0.5f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| // Clear texture framebuffer. | |
| glBindFramebuffer(GL_FRAMEBUFFER, fbo); | |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| ASSERT_GL_NO_ERROR(); | |
| EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 0, 0, 0, | |
| 255); | |
| // BlitFramebuffer from/to RGB framebuffer succeeds. | |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, rgbFbo); | |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo); | |
| glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize, | |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); | |
| ASSERT_GL_NO_ERROR(); | |
| EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 255, 0, | |
| 255, 255); | |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); | |
| glClear(GL_COLOR_BUFFER_BIT); | |
| glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); | |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, rgbFbo); | |
| glBlitFramebufferANGLE(0, 0, bufferSize, bufferSize, 0, 0, bufferSize, bufferSize, | |
| GL_COLOR_BUFFER_BIT, GL_NEAREST); | |
| ASSERT_GL_NO_ERROR(); | |
| glBindFramebuffer(GL_FRAMEBUFFER, rgbFbo); | |
| EXPECT_PIXEL_EQ(static_cast<GLint>(bufferSize) / 2, static_cast<GLint>(bufferSize) / 2, 0, 0, 0, | |
| 255); | |
| glDeleteFramebuffers(1, &rgbFbo); | |
| glDeleteRenderbuffers(1, &rgbRbo); | |
| glDeleteFramebuffers(1, &rgbaFbo); | |
| glDeleteRenderbuffers(1, &rgbaRbo); | |
| glDeleteFramebuffers(1, &fbo); | |
| glDeleteTextures(1, &texture); | |
| d3d11_texture->Release(); | |
| } | |
| // Use this to select which configurations (e.g. which renderer, which GLES major version) these | |
| // tests should be run against. | |
| ANGLE_INSTANTIATE_TEST_ES2(D3DTextureTest); | |
| ANGLE_INSTANTIATE_TEST_ES3(D3DTextureTestES3); | |
| // D3D Debug device reports an error. http://anglebug.com/3513 | |
| // ANGLE_INSTANTIATE_TEST(D3DTextureTestMS, ES2_D3D11()); | |
| } // namespace angle |