| // |
| // Copyright 2018 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. |
| // |
| // MultiviewTest: |
| // Implementation of helpers for multiview testing. |
| // |
| |
| #include "test_utils/MultiviewTest.h" |
| #include "platform/WorkaroundsD3D.h" |
| #include "test_utils/gl_raii.h" |
| |
| namespace angle |
| { |
| |
| GLuint CreateSimplePassthroughProgram(int numViews) |
| { |
| const std::string vsSource = |
| "#version 300 es\n" |
| "#extension GL_OVR_multiview : require\n" |
| "layout(num_views = " + |
| ToString(numViews) + |
| ") in;\n" |
| "layout(location=0) in vec2 vPosition;\n" |
| "void main()\n" |
| "{\n" |
| " gl_PointSize = 1.;\n" |
| " gl_Position = vec4(vPosition.xy, 0.0, 1.0);\n" |
| "}\n"; |
| |
| constexpr char kFS[] = |
| "#version 300 es\n" |
| "#extension GL_OVR_multiview : require\n" |
| "precision mediump float;\n" |
| "out vec4 col;\n" |
| "void main()\n" |
| "{\n" |
| " col = vec4(0,1,0,1);\n" |
| "}\n"; |
| return CompileProgram(vsSource.c_str(), kFS); |
| } |
| |
| void CreateMultiviewBackingTextures(GLenum multiviewLayout, |
| int samples, |
| int viewWidth, |
| int height, |
| int numLayers, |
| std::vector<GLuint> colorTextures, |
| GLuint depthTexture, |
| GLuint depthStencilTexture) |
| { |
| // The same zero data is used to initialize both color and depth/stencil textures. |
| std::vector<GLubyte> textureData; |
| textureData.resize(viewWidth * height * numLayers * 4, 0u); |
| |
| // Multisampling is only supported for layered framebuffers. |
| ASSERT((samples == 0) || multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE); |
| |
| // We can't upload data to multisample textures, so we clear them using a temporary framebuffer |
| // instead. The current framebuffer binding is stored so we can restore it once we're done with |
| // using the temporary framebuffers. |
| GLint restoreDrawFramebuffer; |
| glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &restoreDrawFramebuffer); |
| |
| // Create color and depth textures. |
| switch (multiviewLayout) |
| { |
| case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE: |
| { |
| int textureWidth = viewWidth * numLayers; |
| for (auto colorTexture : colorTextures) |
| { |
| glBindTexture(GL_TEXTURE_2D, colorTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, height, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| } |
| |
| if (depthTexture != 0) |
| { |
| glBindTexture(GL_TEXTURE_2D, depthTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, textureWidth, height, 0, |
| GL_DEPTH_COMPONENT, GL_FLOAT, textureData.data()); |
| } |
| if (depthStencilTexture != 0) |
| { |
| glBindTexture(GL_TEXTURE_2D, depthStencilTexture); |
| glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, textureWidth, height, 0, |
| GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, textureData.data()); |
| } |
| glBindTexture(GL_TEXTURE_2D, 0); |
| break; |
| } |
| case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE: |
| { |
| GLenum texTarget = |
| (samples > 0) ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY_OES : GL_TEXTURE_2D_ARRAY; |
| for (auto colorTexture : colorTextures) |
| { |
| glBindTexture(texTarget, colorTexture); |
| if (samples > 0) |
| { |
| glTexStorage3DMultisampleOES(texTarget, samples, GL_RGBA8, viewWidth, height, |
| numLayers, false); |
| |
| GLFramebuffer tempFbo; |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tempFbo); |
| glClearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| for (int layerIndex = 0; layerIndex < numLayers; ++layerIndex) |
| { |
| glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| colorTexture, 0, layerIndex); |
| glClear(GL_COLOR_BUFFER_BIT); |
| } |
| } |
| else |
| { |
| glTexImage3D(texTarget, 0, GL_RGBA8, viewWidth, height, numLayers, 0, GL_RGBA, |
| GL_UNSIGNED_BYTE, textureData.data()); |
| glTexParameteri(texTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| glTexParameteri(texTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| } |
| } |
| |
| if (depthTexture != 0) |
| { |
| glBindTexture(texTarget, depthTexture); |
| if (samples > 0) |
| { |
| glTexStorage3DMultisampleOES(texTarget, samples, GL_DEPTH_COMPONENT32F, |
| viewWidth, height, numLayers, false); |
| |
| GLFramebuffer tempFbo; |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tempFbo); |
| glClearDepthf(0.0f); |
| for (int layerIndex = 0; layerIndex < numLayers; ++layerIndex) |
| { |
| glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, |
| depthTexture, 0, layerIndex); |
| glClear(GL_DEPTH_BUFFER_BIT); |
| } |
| } |
| else |
| { |
| glTexImage3D(texTarget, 0, GL_DEPTH_COMPONENT32F, viewWidth, height, numLayers, |
| 0, GL_DEPTH_COMPONENT, GL_FLOAT, textureData.data()); |
| } |
| } |
| if (depthStencilTexture != 0) |
| { |
| glBindTexture(texTarget, depthStencilTexture); |
| if (samples > 0) |
| { |
| glTexStorage3DMultisampleOES(texTarget, samples, GL_DEPTH24_STENCIL8, viewWidth, |
| height, numLayers, false); |
| |
| GLFramebuffer tempFbo; |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, tempFbo); |
| glClearDepthf(0.0f); |
| glClearStencil(0); |
| for (int layerIndex = 0; layerIndex < numLayers; ++layerIndex) |
| { |
| glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, |
| depthTexture, 0, layerIndex); |
| glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); |
| } |
| } |
| else |
| { |
| glTexImage3D(texTarget, 0, GL_DEPTH24_STENCIL8, viewWidth, height, numLayers, 0, |
| GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, textureData.data()); |
| } |
| } |
| glBindTexture(texTarget, 0); |
| break; |
| } |
| default: |
| UNREACHABLE(); |
| } |
| ASSERT_GL_NO_ERROR(); |
| |
| glBindFramebuffer(GL_DRAW_FRAMEBUFFER, restoreDrawFramebuffer); |
| } |
| |
| void CreateMultiviewBackingTextures(GLenum multiviewLayout, |
| int samples, |
| int viewWidth, |
| int height, |
| int numLayers, |
| GLuint colorTexture, |
| GLuint depthTexture, |
| GLuint depthStencilTexture) |
| { |
| ASSERT(colorTexture != 0u); |
| std::vector<GLuint> colorTextures(1, colorTexture); |
| CreateMultiviewBackingTextures(multiviewLayout, samples, viewWidth, height, numLayers, |
| colorTextures, depthTexture, depthStencilTexture); |
| } |
| |
| void AttachMultiviewTextures(GLenum target, |
| GLenum multiviewLayout, |
| int viewWidth, |
| int numViews, |
| int baseViewIndex, |
| std::vector<GLuint> colorTextures, |
| GLuint depthTexture, |
| GLuint depthStencilTexture) |
| { |
| ASSERT(multiviewLayout == GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE || (baseViewIndex == 0)); |
| ASSERT(depthTexture == 0u || depthStencilTexture == 0u); |
| switch (multiviewLayout) |
| { |
| case GL_FRAMEBUFFER_MULTIVIEW_SIDE_BY_SIDE_ANGLE: |
| { |
| std::vector<GLint> viewportOffsets(numViews * 2); |
| for (int i = 0u; i < numViews; ++i) |
| { |
| viewportOffsets[i * 2] = i * viewWidth; |
| viewportOffsets[i * 2 + 1] = 0; |
| } |
| for (size_t i = 0; i < colorTextures.size(); ++i) |
| { |
| GLenum attachment = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i); |
| glFramebufferTextureMultiviewSideBySideANGLE(target, attachment, colorTextures[i], |
| 0, numViews, viewportOffsets.data()); |
| } |
| if (depthTexture) |
| { |
| glFramebufferTextureMultiviewSideBySideANGLE( |
| target, GL_DEPTH_ATTACHMENT, depthTexture, 0, numViews, viewportOffsets.data()); |
| } |
| if (depthStencilTexture) |
| { |
| glFramebufferTextureMultiviewSideBySideANGLE(target, GL_DEPTH_STENCIL_ATTACHMENT, |
| depthStencilTexture, 0, numViews, |
| viewportOffsets.data()); |
| } |
| break; |
| } |
| case GL_FRAMEBUFFER_MULTIVIEW_LAYERED_ANGLE: |
| for (size_t i = 0; i < colorTextures.size(); ++i) |
| { |
| GLenum attachment = static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i); |
| glFramebufferTextureMultiviewLayeredANGLE(target, attachment, colorTextures[i], 0, |
| baseViewIndex, numViews); |
| } |
| if (depthTexture) |
| { |
| glFramebufferTextureMultiviewLayeredANGLE(target, GL_DEPTH_ATTACHMENT, depthTexture, |
| 0, baseViewIndex, numViews); |
| } |
| if (depthStencilTexture) |
| { |
| glFramebufferTextureMultiviewLayeredANGLE(target, GL_DEPTH_STENCIL_ATTACHMENT, |
| depthStencilTexture, 0, baseViewIndex, |
| numViews); |
| } |
| break; |
| default: |
| UNREACHABLE(); |
| } |
| } |
| |
| void AttachMultiviewTextures(GLenum target, |
| GLenum multiviewLayout, |
| int viewWidth, |
| int numViews, |
| int baseViewIndex, |
| GLuint colorTexture, |
| GLuint depthTexture, |
| GLuint depthStencilTexture) |
| { |
| ASSERT(colorTexture != 0u); |
| std::vector<GLuint> colorTextures(1, colorTexture); |
| AttachMultiviewTextures(target, multiviewLayout, viewWidth, numViews, baseViewIndex, |
| colorTextures, depthTexture, depthStencilTexture); |
| } |
| |
| std::ostream &operator<<(std::ostream &os, const MultiviewImplementationParams ¶ms) |
| { |
| const PlatformParameters &base = static_cast<const PlatformParameters &>(params); |
| os << base; |
| if (params.mForceUseGeometryShaderOnD3D) |
| { |
| os << "_force_geom_shader"; |
| } |
| else |
| { |
| os << "_vertex_shader"; |
| } |
| return os; |
| } |
| |
| MultiviewImplementationParams VertexShaderOpenGL(GLint majorVersion, GLint minorVersion) |
| { |
| return MultiviewImplementationParams(majorVersion, minorVersion, false, egl_platform::OPENGL()); |
| } |
| |
| MultiviewImplementationParams VertexShaderD3D11(GLint majorVersion, GLint minorVersion) |
| { |
| return MultiviewImplementationParams(majorVersion, minorVersion, false, egl_platform::D3D11()); |
| } |
| |
| MultiviewImplementationParams GeomShaderD3D11(GLint majorVersion, GLint minorVersion) |
| { |
| return MultiviewImplementationParams(majorVersion, minorVersion, true, egl_platform::D3D11()); |
| } |
| |
| void MultiviewTest::overrideWorkaroundsD3D(WorkaroundsD3D *workarounds) |
| { |
| workarounds->selectViewInGeometryShader = GetParam().mForceUseGeometryShaderOnD3D; |
| } |
| |
| } // namespace angle |