| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL ES 2.0 Module |
| * ------------------------------------------------- |
| * |
| * Copyright 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| *//*! |
| * \file |
| * \brief Framebuffer Object Tests. |
| * |
| * Notes: |
| * + Like in API tests, tcu::sgl2s::Context class is used. |
| * + ReferenceContext is used to generate reference images. |
| * + API calls can be logged \todo [pyry] Implement. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "es2fFboRenderTest.hpp" |
| #include "sglrContextUtil.hpp" |
| #include "sglrGLContext.hpp" |
| #include "sglrReferenceContext.hpp" |
| #include "tcuSurface.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuImageCompare.hpp" |
| #include "tcuRenderTarget.hpp" |
| #include "gluPixelTransfer.hpp" |
| #include "gluTextureUtil.hpp" |
| #include "gluStrUtil.hpp" |
| #include "deRandom.hpp" |
| #include "deString.h" |
| |
| #include "glwFunctions.hpp" |
| #include "glwEnums.hpp" |
| |
| using std::vector; |
| using std::string; |
| using tcu::Vec2; |
| using tcu::Vec3; |
| using tcu::Vec4; |
| using tcu::RGBA; |
| using tcu::Surface; |
| using namespace glw; // GL types |
| |
| namespace deqp |
| { |
| namespace gles2 |
| { |
| namespace Functional |
| { |
| |
| // Shaders. |
| |
| class FlatColorShader : public sglr::ShaderProgram |
| { |
| public: |
| FlatColorShader (void) |
| : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration() |
| << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT) |
| << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT) |
| << sglr::pdec::Uniform("u_color", glu::TYPE_FLOAT_VEC4) |
| << sglr::pdec::VertexSource( |
| "attribute highp vec4 a_position;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| "}\n") |
| << sglr::pdec::FragmentSource( |
| "uniform mediump vec4 u_color;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_FragColor = u_color;\n" |
| "}\n")) |
| { |
| } |
| |
| void setColor (sglr::Context& gl, deUint32 program, const tcu::Vec4& color) |
| { |
| gl.useProgram(program); |
| gl.uniform4fv(gl.getUniformLocation(program, "u_color"), 1, color.getPtr()); |
| } |
| |
| void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const |
| { |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| packets[packetNdx]->position = rr::readVertexAttribFloat(inputs[0], packets[packetNdx]->instanceNdx, packets[packetNdx]->vertexNdx); |
| } |
| |
| void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const |
| { |
| const tcu::Vec4 color(m_uniforms[0].value.f4); |
| |
| DE_UNREF(packets); |
| |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| for (int fragNdx = 0; fragNdx < 4; ++fragNdx) |
| rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, color); |
| } |
| }; |
| |
| class SingleTex2DShader : public sglr::ShaderProgram |
| { |
| public: |
| SingleTex2DShader (void) |
| : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration() |
| << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT) |
| << sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT) |
| << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT) |
| << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT) |
| << sglr::pdec::Uniform("u_sampler0", glu::TYPE_SAMPLER_2D) |
| << sglr::pdec::VertexSource( |
| "attribute highp vec4 a_position;\n" |
| "attribute mediump vec2 a_coord;\n" |
| "varying mediump vec2 v_coord;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_coord = a_coord;\n" |
| "}\n") |
| << sglr::pdec::FragmentSource( |
| "uniform sampler2D u_sampler0;\n" |
| "varying mediump vec2 v_coord;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_FragColor = texture2D(u_sampler0, v_coord);\n" |
| "}\n")) |
| { |
| } |
| |
| void setUnit (sglr::Context& gl, deUint32 program, int unitNdx) |
| { |
| gl.useProgram(program); |
| gl.uniform1i(gl.getUniformLocation(program, "u_sampler0"), unitNdx); |
| } |
| |
| void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const |
| { |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| { |
| rr::VertexPacket& packet = *packets[packetNdx]; |
| |
| packet.position = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx); |
| packet.outputs[0] = rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx); |
| } |
| } |
| |
| void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const |
| { |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| for (int fragNdx = 0; fragNdx < 4; ++fragNdx) |
| { |
| const tcu::Vec4 v_coord = rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx); |
| const float lod = 0.0f; |
| |
| rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, this->m_uniforms[0].sampler.tex2D->sample(v_coord.x(), v_coord.y(), lod)); |
| } |
| } |
| |
| }; |
| |
| class MixTexturesShader : public sglr::ShaderProgram |
| { |
| public: |
| MixTexturesShader (void) |
| : sglr::ShaderProgram(sglr::pdec::ShaderProgramDeclaration() |
| << sglr::pdec::VertexAttribute("a_position", rr::GENERICVECTYPE_FLOAT) |
| << sglr::pdec::VertexAttribute("a_coord", rr::GENERICVECTYPE_FLOAT) |
| << sglr::pdec::VertexToFragmentVarying(rr::GENERICVECTYPE_FLOAT) |
| << sglr::pdec::FragmentOutput(rr::GENERICVECTYPE_FLOAT) |
| << sglr::pdec::Uniform("u_sampler0", glu::TYPE_SAMPLER_2D) |
| << sglr::pdec::Uniform("u_sampler1", glu::TYPE_SAMPLER_2D) |
| << sglr::pdec::VertexSource( |
| "attribute highp vec4 a_position;\n" |
| "attribute mediump vec2 a_coord;\n" |
| "varying mediump vec2 v_coord;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_Position = a_position;\n" |
| " v_coord = a_coord;\n" |
| "}\n") |
| << sglr::pdec::FragmentSource( |
| "uniform sampler2D u_sampler0;\n" |
| "uniform sampler2D u_sampler1;\n" |
| "varying mediump vec2 v_coord;\n" |
| "void main (void)\n" |
| "{\n" |
| " gl_FragColor = texture2D(u_sampler0, v_coord)*0.5 + texture2D(u_sampler1, v_coord)*0.5;\n" |
| "}\n")) |
| { |
| } |
| |
| void setUnits (sglr::Context& gl, deUint32 program, int unit0, int unit1) |
| { |
| gl.useProgram(program); |
| gl.uniform1i(gl.getUniformLocation(program, "u_sampler0"), unit0); |
| gl.uniform1i(gl.getUniformLocation(program, "u_sampler1"), unit1); |
| } |
| |
| void shadeVertices (const rr::VertexAttrib* inputs, rr::VertexPacket* const* packets, const int numPackets) const |
| { |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| { |
| rr::VertexPacket& packet = *packets[packetNdx]; |
| |
| packet.position = rr::readVertexAttribFloat(inputs[0], packet.instanceNdx, packet.vertexNdx); |
| packet.outputs[0] = rr::readVertexAttribFloat(inputs[1], packet.instanceNdx, packet.vertexNdx); |
| } |
| } |
| |
| void shadeFragments (rr::FragmentPacket* packets, const int numPackets, const rr::FragmentShadingContext& context) const |
| { |
| for (int packetNdx = 0; packetNdx < numPackets; ++packetNdx) |
| for (int fragNdx = 0; fragNdx < 4; ++fragNdx) |
| { |
| const tcu::Vec4 v_coord = rr::readVarying<float>(packets[packetNdx], context, 0, fragNdx); |
| const float lod = 0.0f; |
| |
| rr::writeFragmentOutput(context, packetNdx, fragNdx, 0, this->m_uniforms[0].sampler.tex2D->sample(v_coord.x(), v_coord.y(), lod) * 0.5f |
| + this->m_uniforms[1].sampler.tex2D->sample(v_coord.x(), v_coord.y(), lod) * 0.5f); |
| } |
| } |
| }; |
| |
| // Framebuffer config. |
| |
| class FboConfig |
| { |
| public: |
| FboConfig (void) |
| : colorbufferType (GL_NONE) |
| , colorbufferFormat (GL_NONE) |
| , depthbufferType (GL_NONE) |
| , depthbufferFormat (GL_NONE) |
| , stencilbufferType (GL_NONE) |
| , stencilbufferFormat (GL_NONE) |
| { |
| } |
| |
| std::string getName (void) const; |
| |
| GLenum colorbufferType; //!< GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP, GL_RENDERBUFFER |
| GLenum colorbufferFormat; //!< Internal format for color buffer texture or renderbuffer |
| |
| GLenum depthbufferType; //!< GL_RENDERBUFFER |
| GLenum depthbufferFormat; |
| |
| GLenum stencilbufferType; //!< GL_RENDERBUFFER |
| GLenum stencilbufferFormat; |
| |
| private: |
| static const char* getFormatName (GLenum format); |
| }; |
| |
| const char* FboConfig::getFormatName (GLenum format) |
| { |
| switch (format) |
| { |
| case GL_RGB: return "rgb"; |
| case GL_RGBA: return "rgba"; |
| case GL_ALPHA: return "alpha"; |
| case GL_LUMINANCE: return "luminance"; |
| case GL_LUMINANCE_ALPHA: return "luminance_alpha"; |
| case GL_RGB565: return "rgb565"; |
| case GL_RGB5_A1: return "rgb5_a1"; |
| case GL_RGBA4: return "rgba4"; |
| case GL_RGBA16F: return "rgba16f"; |
| case GL_RGB16F: return "rgb16f"; |
| case GL_DEPTH_COMPONENT16: return "depth_component16"; |
| case GL_STENCIL_INDEX8: return "stencil_index8"; |
| default: DE_ASSERT(false); return DE_NULL; |
| } |
| } |
| |
| std::string FboConfig::getName (void) const |
| { |
| std::string name = ""; |
| |
| if (colorbufferType != GL_NONE) |
| { |
| switch (colorbufferType) |
| { |
| case GL_TEXTURE_2D: name += "tex2d_"; break; |
| case GL_TEXTURE_CUBE_MAP: name += "texcube_"; break; |
| case GL_RENDERBUFFER: name += "rbo_"; break; |
| default: DE_ASSERT(false); break; |
| } |
| name += getFormatName(colorbufferFormat); |
| } |
| |
| if (depthbufferType != GL_NONE) |
| { |
| DE_ASSERT(depthbufferType == GL_RENDERBUFFER); |
| if (name.length() > 0) |
| name += "_"; |
| name += getFormatName(depthbufferFormat); |
| } |
| |
| if (stencilbufferType != GL_NONE) |
| { |
| DE_ASSERT(stencilbufferType == GL_RENDERBUFFER); |
| if (name.length() > 0) |
| name += "_"; |
| name += getFormatName(stencilbufferFormat); |
| } |
| |
| return name; |
| } |
| |
| class FboIncompleteException : public tcu::TestError |
| { |
| public: |
| FboIncompleteException (const FboConfig& config, GLenum reason, const char* file, int line); |
| virtual ~FboIncompleteException (void) throw() {} |
| |
| const FboConfig& getConfig (void) const { return m_config; } |
| GLenum getReason (void) const { return m_reason; } |
| |
| private: |
| FboConfig m_config; |
| GLenum m_reason; |
| }; |
| |
| static const char* getFboIncompleteReasonName (GLenum reason) |
| { |
| switch (reason) |
| { |
| case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"; |
| case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"; |
| case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: return "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS"; |
| case GL_FRAMEBUFFER_UNSUPPORTED: return "GL_FRAMEBUFFER_UNSUPPORTED"; |
| case GL_FRAMEBUFFER_COMPLETE: return "GL_FRAMEBUFFER_COMPLETE"; |
| default: return "UNKNOWN"; |
| } |
| } |
| |
| FboIncompleteException::FboIncompleteException (const FboConfig& config, GLenum reason, const char* file, int line) |
| : TestError("Framebuffer is not complete", getFboIncompleteReasonName(reason), file, line) |
| , m_config(config) |
| , m_reason(reason) |
| { |
| } |
| |
| class Framebuffer |
| { |
| public: |
| Framebuffer (sglr::Context& context, const FboConfig& config, int width, int height, deUint32 fbo = 0, deUint32 colorbuffer = 0, deUint32 depthbuffer = 0, deUint32 stencilbuffer = 0); |
| ~Framebuffer (void); |
| |
| const FboConfig& getConfig (void) const { return m_config; } |
| deUint32 getFramebuffer (void) const { return m_framebuffer; } |
| deUint32 getColorbuffer (void) const { return m_colorbuffer; } |
| deUint32 getDepthbuffer (void) const { return m_depthbuffer; } |
| deUint32 getStencilbuffer (void) const { return m_stencilbuffer; } |
| |
| void checkCompleteness (void); |
| |
| private: |
| void createRbo (deUint32& name, GLenum format, int width, int height); |
| void destroyBuffer (deUint32 name, GLenum type); |
| |
| FboConfig m_config; |
| sglr::Context& m_context; |
| deUint32 m_framebuffer; |
| deUint32 m_colorbuffer; |
| deUint32 m_depthbuffer; |
| deUint32 m_stencilbuffer; |
| }; |
| |
| static bool isExtensionSupported (sglr::Context& context, const char* name) |
| { |
| std::istringstream extensions(context.getString(GL_EXTENSIONS)); |
| std::string extension; |
| |
| while (std::getline(extensions, extension, ' ')) |
| { |
| if (extension == name) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| static void checkColorFormatSupport (sglr::Context& context, deUint32 sizedFormat) |
| { |
| switch (sizedFormat) |
| { |
| case GL_RGBA16F: |
| case GL_RGB16F: |
| case GL_RG16F: |
| case GL_R16F: |
| if (!isExtensionSupported(context, "GL_EXT_color_buffer_half_float")) |
| throw tcu::NotSupportedError("GL_EXT_color_buffer_half_float is not supported"); |
| |
| default: |
| break; |
| } |
| } |
| |
| Framebuffer::Framebuffer (sglr::Context& context, const FboConfig& config, int width, int height, deUint32 fbo, deUint32 colorbuffer, deUint32 depthbuffer, deUint32 stencilbuffer) |
| : m_config (config) |
| , m_context (context) |
| , m_framebuffer (fbo) |
| , m_colorbuffer (colorbuffer) |
| , m_depthbuffer (depthbuffer) |
| , m_stencilbuffer (stencilbuffer) |
| { |
| // Verify that color format is supported |
| checkColorFormatSupport(context, config.colorbufferFormat); |
| |
| if (m_framebuffer == 0) |
| context.genFramebuffers(1, &m_framebuffer); |
| context.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); |
| |
| switch (m_config.colorbufferType) |
| { |
| case GL_TEXTURE_2D: |
| if (m_colorbuffer == 0) |
| context.genTextures(1, &m_colorbuffer); |
| context.bindTexture(GL_TEXTURE_2D, m_colorbuffer); |
| context.texImage2D(GL_TEXTURE_2D, 0, m_config.colorbufferFormat, width, height); |
| context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| |
| if (!deIsPowerOfTwo32(width) || !deIsPowerOfTwo32(height)) |
| { |
| // Set wrap mode to clamp for NPOT FBOs |
| context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| } |
| |
| context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorbuffer, 0); |
| break; |
| |
| case GL_TEXTURE_CUBE_MAP: |
| DE_FATAL("TODO"); |
| break; |
| |
| case GL_RENDERBUFFER: |
| createRbo(m_colorbuffer, m_config.colorbufferFormat, width, height); |
| context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_colorbuffer); |
| break; |
| |
| default: |
| DE_ASSERT(m_config.colorbufferType == GL_NONE); |
| break; |
| } |
| |
| if (m_config.depthbufferType == GL_RENDERBUFFER) |
| { |
| createRbo(m_depthbuffer, m_config.depthbufferFormat, width, height); |
| context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthbuffer); |
| } |
| else |
| DE_ASSERT(m_config.depthbufferType == GL_NONE); |
| |
| if (m_config.stencilbufferType == GL_RENDERBUFFER) |
| { |
| createRbo(m_stencilbuffer, m_config.stencilbufferFormat, width, height); |
| context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_stencilbuffer); |
| } |
| else |
| DE_ASSERT(m_config.stencilbufferType == GL_NONE); |
| |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| } |
| |
| Framebuffer::~Framebuffer (void) |
| { |
| m_context.deleteFramebuffers(1, &m_framebuffer); |
| destroyBuffer(m_colorbuffer, m_config.colorbufferType); |
| destroyBuffer(m_depthbuffer, m_config.depthbufferType); |
| destroyBuffer(m_stencilbuffer, m_config.stencilbufferType); |
| } |
| |
| void Framebuffer::checkCompleteness (void) |
| { |
| m_context.bindFramebuffer(GL_FRAMEBUFFER, m_framebuffer); |
| GLenum status = m_context.checkFramebufferStatus(GL_FRAMEBUFFER); |
| m_context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| if (status != GL_FRAMEBUFFER_COMPLETE) |
| throw FboIncompleteException(m_config, status, __FILE__, __LINE__); |
| } |
| |
| void Framebuffer::createRbo (deUint32& name, GLenum format, int width, int height) |
| { |
| if (name == 0) |
| m_context.genRenderbuffers(1, &name); |
| m_context.bindRenderbuffer(GL_RENDERBUFFER, name); |
| m_context.renderbufferStorage(GL_RENDERBUFFER, format, width, height); |
| } |
| |
| void Framebuffer::destroyBuffer (deUint32 name, GLenum type) |
| { |
| if (type == GL_TEXTURE_2D || type == GL_TEXTURE_CUBE_MAP) |
| m_context.deleteTextures(1, &name); |
| else if (type == GL_RENDERBUFFER) |
| m_context.deleteRenderbuffers(1, &name); |
| else |
| DE_ASSERT(type == GL_NONE); |
| } |
| |
| static void createMetaballsTex2D (sglr::Context& context, deUint32 name, GLenum format, GLenum dataType, int width, int height) |
| { |
| tcu::TextureFormat texFormat = glu::mapGLTransferFormat(format, dataType); |
| tcu::TextureLevel level (texFormat, width, height); |
| |
| tcu::fillWithMetaballs(level.getAccess(), 5, name ^ width ^ height); |
| |
| context.bindTexture(GL_TEXTURE_2D, name); |
| context.texImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, dataType, level.getAccess().getDataPtr()); |
| context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| } |
| |
| static void createQuadsTex2D (sglr::Context& context, deUint32 name, GLenum format, GLenum dataType, int width, int height) |
| { |
| tcu::TextureFormat texFormat = glu::mapGLTransferFormat(format, dataType); |
| tcu::TextureLevel level (texFormat, width, height); |
| |
| tcu::fillWithRGBAQuads(level.getAccess()); |
| |
| context.bindTexture(GL_TEXTURE_2D, name); |
| context.texImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, dataType, level.getAccess().getDataPtr()); |
| context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| } |
| |
| class FboRenderCase : public TestCase |
| { |
| public: |
| FboRenderCase (Context& context, const char* name, const char* description, const FboConfig& config); |
| virtual ~FboRenderCase (void) {} |
| |
| virtual IterateResult iterate (void); |
| virtual void render (sglr::Context& fboContext, Surface& dst) = DE_NULL; |
| |
| const FboConfig& getConfig (void) const { return m_config; } |
| |
| static bool isConfigSupported (const FboConfig& config) { DE_UNREF(config); return true; } |
| |
| private: |
| FboConfig m_config; |
| }; |
| |
| FboRenderCase::FboRenderCase (Context& context, const char* name, const char* description, const FboConfig& config) |
| : TestCase(context, name, description) |
| , m_config(config) |
| { |
| } |
| |
| TestCase::IterateResult FboRenderCase::iterate (void) |
| { |
| Vec4 clearColor (0.125f, 0.25f, 0.5f, 1.0f); |
| glu::RenderContext& renderCtx = m_context.getRenderContext(); |
| const tcu::RenderTarget& renderTarget = m_context.getRenderTarget(); |
| tcu::TestLog& log = m_testCtx.getLog(); |
| const char* failReason = DE_NULL; |
| |
| // Position & size for context |
| deRandom rnd; |
| deRandom_init(&rnd, deStringHash(getName())); |
| |
| int width = deMin32(renderTarget.getWidth(), 128); |
| int height = deMin32(renderTarget.getHeight(), 128); |
| int xMax = renderTarget.getWidth()-width+1; |
| int yMax = renderTarget.getHeight()-height+1; |
| int x = deRandom_getUint32(&rnd) % xMax; |
| int y = deRandom_getUint32(&rnd) % yMax; |
| |
| tcu::Surface gles2Frame (width, height); |
| tcu::Surface refFrame (width, height); |
| GLenum gles2Error; |
| GLenum refError; |
| |
| // Render using GLES2 |
| try |
| { |
| sglr::GLContext context(renderCtx, log, sglr::GLCONTEXT_LOG_CALLS, tcu::IVec4(x, y, width, height)); |
| |
| context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w()); |
| context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| render(context, gles2Frame); // Call actual render func |
| gles2Error = context.getError(); |
| } |
| catch (const FboIncompleteException& e) |
| { |
| if (e.getReason() == GL_FRAMEBUFFER_UNSUPPORTED) |
| { |
| // Mark test case as unsupported |
| log << e; |
| m_testCtx.setTestResult(QP_TEST_RESULT_NOT_SUPPORTED, "Not supported"); |
| return STOP; |
| } |
| else |
| throw; // Propagate error |
| } |
| |
| // Render reference image |
| { |
| sglr::ReferenceContextBuffers buffers (tcu::PixelFormat(8,8,8,renderTarget.getPixelFormat().alphaBits?8:0), renderTarget.getDepthBits(), renderTarget.getStencilBits(), width, height); |
| sglr::ReferenceContext context (sglr::ReferenceContextLimits(renderCtx), buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer()); |
| |
| context.clearColor(clearColor.x(), clearColor.y(), clearColor.z(), clearColor.w()); |
| context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| render(context, refFrame); |
| refError = context.getError(); |
| } |
| |
| // Compare error codes |
| bool errorCodesOk = (gles2Error == refError); |
| |
| if (!errorCodesOk) |
| { |
| log << tcu::TestLog::Message << "Error code mismatch: got " << glu::getErrorStr(gles2Error) << ", expected " << glu::getErrorStr(refError) << tcu::TestLog::EndMessage; |
| failReason = "Got unexpected error"; |
| } |
| |
| // Compare images |
| const float threshold = 0.03f; |
| bool imagesOk = tcu::fuzzyCompare(log, "ComparisonResult", "Image comparison result", refFrame, gles2Frame, threshold, tcu::COMPARE_LOG_RESULT); |
| |
| if (!imagesOk && !failReason) |
| failReason = "Image comparison failed"; |
| |
| // Store test result |
| bool isOk = errorCodesOk && imagesOk; |
| m_testCtx.setTestResult(isOk ? QP_TEST_RESULT_PASS : QP_TEST_RESULT_FAIL, |
| isOk ? "Pass" : failReason); |
| |
| return STOP; |
| } |
| |
| namespace FboCases |
| { |
| |
| class ColorClearsTest : public FboRenderCase |
| { |
| public: |
| ColorClearsTest (Context& context, const FboConfig& config); |
| ~ColorClearsTest (void) {} |
| |
| void render (sglr::Context& context, Surface& dst); |
| }; |
| |
| ColorClearsTest::ColorClearsTest (Context& context, const FboConfig& config) |
| : FboRenderCase(context, config.getName().c_str(), "Color buffer clears", config) |
| { |
| } |
| |
| void ColorClearsTest::render (sglr::Context& context, Surface& dst) |
| { |
| int width = 128; |
| int height = 128; |
| deRandom rnd; |
| |
| deRandom_init(&rnd, 0); |
| |
| // Create framebuffer |
| Framebuffer fbo(context, getConfig(), width, height); |
| fbo.checkCompleteness(); |
| |
| // Clear fbo |
| context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer()); |
| context.viewport(0, 0, width, height); |
| context.clearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| // Enable scissor test. |
| context.enable(GL_SCISSOR_TEST); |
| |
| // Do 10 random color clears |
| for (int i = 0; i < 15; i++) |
| { |
| int cX = (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % width; |
| int cY = (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % height; |
| int cWidth = (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % (width-cX); |
| int cHeight = (int)(deRandom_getUint32(&rnd) & 0x7fffffff) % (height-cY); |
| Vec4 color = RGBA(deRandom_getUint32(&rnd)).toVec(); |
| |
| context.scissor(cX, cY, cWidth, cHeight); |
| context.clearColor(color.x(), color.y(), color.z(), color.w()); |
| context.clear(GL_COLOR_BUFFER_BIT); |
| } |
| |
| // Disable scissor. |
| context.disable(GL_SCISSOR_TEST); |
| |
| if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D) |
| { |
| // Unbind fbo |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| // Draw to screen |
| SingleTex2DShader shader; |
| deUint32 shaderID = context.createProgram(&shader); |
| |
| shader.setUnit(context, shaderID, 0); |
| |
| context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer()); |
| context.viewport(0, 0, context.getWidth(), context.getHeight()); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| // Read from screen |
| context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight()); |
| } |
| else |
| { |
| // clear alpha channel for GL_RGB5_A1 format because test |
| // thresholds for the alpha channel do not account for dithering |
| if(getConfig().colorbufferFormat == GL_RGB5_A1) |
| { |
| context.colorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); |
| context.clearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT); |
| context.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| } |
| |
| // Read from fbo |
| context.readPixels(dst, 0, 0, width, height); |
| } |
| } |
| |
| class IntersectingQuadsTest : public FboRenderCase |
| { |
| public: |
| IntersectingQuadsTest (Context& context, const FboConfig& config, bool npot = false); |
| virtual ~IntersectingQuadsTest (void) {} |
| |
| virtual void render (sglr::Context& context, Surface& dst); |
| |
| static bool isConfigSupported (const FboConfig& config); |
| |
| private: |
| int m_fboWidth; |
| int m_fboHeight; |
| }; |
| |
| class IntersectingQuadsNpotTest : public IntersectingQuadsTest |
| { |
| public: |
| IntersectingQuadsNpotTest (Context& context, const FboConfig& config) |
| : IntersectingQuadsTest(context, config, true) |
| { |
| } |
| }; |
| |
| IntersectingQuadsTest::IntersectingQuadsTest (Context& context, const FboConfig& config, bool npot) |
| : FboRenderCase (context, (string(npot ? "npot_" : "") + config.getName()).c_str(), "Intersecting textured quads", config) |
| , m_fboWidth (npot ? 127 : 128) |
| , m_fboHeight (npot ? 95 : 128) |
| { |
| } |
| |
| bool IntersectingQuadsTest::isConfigSupported (const FboConfig& config) |
| { |
| // \note Disabled for stencil configurations since doesn't exercise stencil buffer |
| return config.depthbufferType != GL_NONE && |
| config.stencilbufferType == GL_NONE; |
| } |
| |
| void IntersectingQuadsTest::render (sglr::Context& ctx, Surface& dst) |
| { |
| SingleTex2DShader texShader; |
| deUint32 texShaderID = ctx.createProgram(&texShader); |
| |
| deUint32 metaballsTex = 1; |
| deUint32 quadsTex = 2; |
| |
| createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64); |
| createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64); |
| |
| int width = m_fboWidth; |
| int height = m_fboHeight; |
| Framebuffer fbo(ctx, getConfig(), width, height); |
| fbo.checkCompleteness(); |
| |
| // Setup shaders |
| texShader.setUnit(ctx, texShaderID, 0); |
| |
| // Draw scene |
| ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer()); |
| ctx.viewport(0, 0, width, height); |
| ctx.clearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| ctx.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| ctx.enable(GL_DEPTH_TEST); |
| |
| ctx.bindTexture(GL_TEXTURE_2D, metaballsTex); |
| sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f)); |
| |
| ctx.bindTexture(GL_TEXTURE_2D, quadsTex); |
| sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 1.0f), Vec3(1.0f, 1.0f, -1.0f)); |
| |
| ctx.disable(GL_DEPTH_TEST); |
| |
| if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D) |
| { |
| // Unbind fbo |
| ctx.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| // Draw to screen |
| ctx.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer()); |
| ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight()); |
| sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| // Read from screen |
| ctx.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight()); |
| } |
| else |
| { |
| // Read from fbo |
| ctx.readPixels(dst, 0, 0, width, height); |
| } |
| } |
| |
| class MixTest : public FboRenderCase |
| { |
| public: |
| MixTest (Context& context, const FboConfig& config, bool npot = false); |
| virtual ~MixTest (void) {} |
| |
| void render (sglr::Context& context, Surface& dst); |
| |
| static bool isConfigSupported (const FboConfig& config); |
| |
| private: |
| int m_fboAWidth; |
| int m_fboAHeight; |
| int m_fboBWidth; |
| int m_fboBHeight; |
| }; |
| |
| class MixNpotTest : public MixTest |
| { |
| public: |
| MixNpotTest (Context& context, const FboConfig& config) |
| : MixTest(context, config, true) |
| { |
| } |
| }; |
| |
| MixTest::MixTest (Context& context, const FboConfig& config, bool npot) |
| : FboRenderCase (context, (string(npot ? "mix_npot_" : "mix_") + config.getName()).c_str(), "Use two fbos as sources in draw operation", config) |
| , m_fboAWidth (npot ? 127 : 128) |
| , m_fboAHeight (npot ? 95 : 128) |
| , m_fboBWidth (npot ? 55 : 64) |
| , m_fboBHeight (npot ? 63 : 64) |
| { |
| } |
| |
| bool MixTest::isConfigSupported (const FboConfig& config) |
| { |
| // \note Disabled for stencil configurations since doesn't exercise stencil buffer |
| return config.colorbufferType == GL_TEXTURE_2D && |
| config.stencilbufferType == GL_NONE; |
| } |
| |
| void MixTest::render (sglr::Context& context, Surface& dst) |
| { |
| SingleTex2DShader singleTexShader; |
| MixTexturesShader mixShader; |
| |
| deUint32 singleTexShaderID = context.createProgram(&singleTexShader); |
| deUint32 mixShaderID = context.createProgram(&mixShader); |
| |
| // Texture with metaballs |
| deUint32 metaballsTex = 1; |
| context.pixelStorei(GL_UNPACK_ALIGNMENT, 1); |
| createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64); |
| |
| // Setup shaders |
| singleTexShader.setUnit(context, singleTexShaderID, 0); |
| mixShader.setUnits(context, mixShaderID, 0, 1); |
| |
| // Fbo, quad with metaballs texture |
| Framebuffer fboA(context, getConfig(), m_fboAWidth, m_fboAHeight); |
| fboA.checkCompleteness(); |
| context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer()); |
| context.viewport(0, 0, m_fboAWidth, m_fboAHeight); |
| context.clearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| context.bindTexture(GL_TEXTURE_2D, metaballsTex); |
| sglr::drawQuad(context, singleTexShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| // Fbo, color clears |
| Framebuffer fboB(context, getConfig(), m_fboBWidth, m_fboBHeight); |
| fboB.checkCompleteness(); |
| context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer()); |
| context.viewport(0, 0, m_fboBWidth, m_fboBHeight); |
| context.enable(GL_SCISSOR_TEST); |
| context.scissor(0, 0, 32, 64); |
| context.clearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT); |
| context.scissor(32, 0, 32, 64); |
| context.clearColor(0.0f, 1.0f, 0.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT); |
| context.disable(GL_SCISSOR_TEST); |
| |
| // Final mix op |
| context.activeTexture(GL_TEXTURE0); |
| context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer()); |
| context.activeTexture(GL_TEXTURE1); |
| context.bindTexture(GL_TEXTURE_2D, fboB.getColorbuffer()); |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| context.viewport(0, 0, context.getWidth(), context.getHeight()); |
| sglr::drawQuad(context, mixShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight()); |
| } |
| |
| class BlendTest : public FboRenderCase |
| { |
| public: |
| BlendTest (Context& context, const FboConfig& config, bool npot = false); |
| virtual ~BlendTest (void) {} |
| |
| void render (sglr::Context& context, Surface& dst); |
| |
| static bool isConfigSupported (const FboConfig& config); |
| |
| private: |
| int m_fboWidth; |
| int m_fboHeight; |
| }; |
| |
| class BlendNpotTest : public BlendTest |
| { |
| public: |
| BlendNpotTest (Context& context, const FboConfig& config) |
| : BlendTest(context, config, true) |
| { |
| } |
| }; |
| |
| BlendTest::BlendTest (Context& context, const FboConfig& config, bool npot) |
| : FboRenderCase (context, (string(npot ? "blend_npot_" : "blend_") + config.getName()).c_str(), "Blend to fbo", config) |
| , m_fboWidth (npot ? 111 : 128) |
| , m_fboHeight (npot ? 122 : 128) |
| { |
| } |
| |
| bool BlendTest::isConfigSupported (const FboConfig& config) |
| { |
| // \note Disabled for stencil configurations since doesn't exercise stencil buffer |
| return config.stencilbufferType == GL_NONE; |
| } |
| |
| void BlendTest::render (sglr::Context& context, Surface& dst) |
| { |
| SingleTex2DShader shader; |
| deUint32 shaderID = context.createProgram(&shader); |
| int width = m_fboWidth; |
| int height = m_fboHeight; |
| deUint32 metaballsTex = 1; |
| |
| createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, 64, 64); |
| |
| Framebuffer fbo(context, getConfig(), width, height); |
| fbo.checkCompleteness(); |
| |
| shader.setUnit(context, shaderID, 0); |
| |
| context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer()); |
| context.viewport(0, 0, width, height); |
| context.bindTexture(GL_TEXTURE_2D, metaballsTex); |
| context.clearColor(0.6f, 0.0f, 0.6f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| context.enable(GL_BLEND); |
| context.blendEquation(GL_FUNC_ADD); |
| context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| context.disable(GL_BLEND); |
| |
| if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D) |
| { |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer()); |
| context.viewport(0, 0, context.getWidth(), context.getHeight()); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight()); |
| } |
| else |
| context.readPixels(dst, 0, 0, width, height); |
| } |
| |
| class StencilClearsTest : public FboRenderCase |
| { |
| public: |
| StencilClearsTest (Context& context, const FboConfig& config); |
| virtual ~StencilClearsTest (void) {}; |
| |
| void render (sglr::Context& context, Surface& dst); |
| |
| static bool isConfigSupported (const FboConfig& config); |
| }; |
| |
| StencilClearsTest::StencilClearsTest (Context& context, const FboConfig& config) |
| : FboRenderCase(context, config.getName().c_str(), "Stencil clears", config) |
| { |
| } |
| |
| void StencilClearsTest::render (sglr::Context& context, Surface& dst) |
| { |
| SingleTex2DShader shader; |
| deUint32 shaderID = context.createProgram(&shader); |
| int width = 128; |
| int height = 128; |
| deUint32 quadsTex = 1; |
| deUint32 metaballsTex = 2; |
| |
| createQuadsTex2D(context, quadsTex, GL_RGBA, GL_UNSIGNED_BYTE, width, height); |
| createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, width, height); |
| |
| Framebuffer fbo(context, getConfig(), width, height); |
| fbo.checkCompleteness(); |
| |
| // Bind framebuffer and clear |
| context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer()); |
| context.viewport(0, 0, width, height); |
| context.clearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| // Do stencil clears |
| context.enable(GL_SCISSOR_TEST); |
| context.scissor(10, 16, 32, 120); |
| context.clearStencil(1); |
| context.clear(GL_STENCIL_BUFFER_BIT); |
| context.scissor(16, 32, 100, 64); |
| context.clearStencil(2); |
| context.clear(GL_STENCIL_BUFFER_BIT); |
| context.disable(GL_SCISSOR_TEST); |
| |
| // Draw 2 textures with stecil tests |
| context.activeTexture(GL_TEXTURE0); |
| context.bindTexture(GL_TEXTURE_2D, quadsTex); |
| context.activeTexture(GL_TEXTURE1); |
| context.bindTexture(GL_TEXTURE_2D, metaballsTex); |
| |
| context.enable(GL_STENCIL_TEST); |
| context.stencilFunc(GL_EQUAL, 1, 0xffffffffu); |
| shader.setUnit(context, shaderID, 0); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| context.stencilFunc(GL_EQUAL, 2, 0xffffffffu); |
| shader.setUnit(context, shaderID, 1); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| context.disable(GL_STENCIL_TEST); |
| |
| if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D) |
| { |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| context.activeTexture(GL_TEXTURE0); |
| context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer()); |
| context.viewport(0, 0, context.getWidth(), context.getHeight()); |
| shader.setUnit(context, shaderID, 0); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight()); |
| } |
| else |
| { |
| // clear alpha channel for GL_RGB5_A1 format because test |
| // thresholds for the alpha channel do not account for dithering |
| if(getConfig().colorbufferFormat == GL_RGB5_A1) |
| { |
| context.colorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); |
| context.clearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT); |
| context.colorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); |
| } |
| |
| context.readPixels(dst, 0, 0, width, height); |
| } |
| } |
| |
| bool StencilClearsTest::isConfigSupported (const FboConfig& config) |
| { |
| return config.stencilbufferType != GL_NONE; |
| } |
| |
| class StencilTest : public FboRenderCase |
| { |
| public: |
| StencilTest (Context& context, const FboConfig& config, bool npot = false); |
| virtual ~StencilTest (void) {}; |
| |
| void render (sglr::Context& context, Surface& dst); |
| |
| static bool isConfigSupported (const FboConfig& config); |
| |
| private: |
| int m_fboWidth; |
| int m_fboHeight; |
| }; |
| |
| class StencilNpotTest : public StencilTest |
| { |
| public: |
| StencilNpotTest (Context& context, const FboConfig& config) |
| : StencilTest(context, config, true) |
| { |
| } |
| }; |
| |
| StencilTest::StencilTest (Context& context, const FboConfig& config, bool npot) |
| : FboRenderCase (context, (string(npot ? "npot_" : "") + config.getName()).c_str(), "Stencil ops", config) |
| , m_fboWidth (npot ? 99 : 128) |
| , m_fboHeight (npot ? 110 : 128) |
| { |
| } |
| |
| bool StencilTest::isConfigSupported (const FboConfig& config) |
| { |
| return config.stencilbufferType != GL_NONE; |
| } |
| |
| void StencilTest::render (sglr::Context& ctx, Surface& dst) |
| { |
| FlatColorShader colorShader; |
| SingleTex2DShader texShader; |
| deUint32 colorShaderID = ctx.createProgram(&colorShader); |
| deUint32 texShaderID = ctx.createProgram(&texShader); |
| int width = m_fboWidth; |
| int height = m_fboHeight; |
| int texWidth = 64; |
| int texHeight = 64; |
| deUint32 quadsTex = 1; |
| deUint32 metaballsTex = 2; |
| bool depth = getConfig().depthbufferType != GL_NONE; |
| |
| createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight); |
| createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, texWidth, texHeight); |
| |
| Framebuffer fbo(ctx, getConfig(), width, height); |
| fbo.checkCompleteness(); |
| |
| // Bind framebuffer and clear |
| ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer()); |
| ctx.viewport(0, 0, width, height); |
| ctx.clearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| ctx.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| // Render intersecting quads - increment stencil on depth pass |
| ctx.enable(GL_DEPTH_TEST); |
| ctx.enable(GL_STENCIL_TEST); |
| ctx.stencilFunc(GL_ALWAYS, 0, 0xffu); |
| ctx.stencilOp(GL_KEEP, GL_KEEP, GL_INCR); |
| |
| colorShader.setColor(ctx, colorShaderID, Vec4(0.0f, 0.0f, 1.0f, 1.0f)); |
| sglr::drawQuad(ctx, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f)); |
| |
| ctx.bindTexture(GL_TEXTURE_2D, quadsTex); |
| texShader.setUnit(ctx, texShaderID, 0); |
| sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(+1.0f, +1.0f, +1.0f)); |
| |
| // Draw quad with stencil test (stencil == 1 or 2 depending on depth) - decrement on stencil failure |
| ctx.disable(GL_DEPTH_TEST); |
| ctx.stencilFunc(GL_EQUAL, depth ? 2 : 1, 0xffu); |
| ctx.stencilOp(GL_DECR, GL_KEEP, GL_KEEP); |
| colorShader.setColor(ctx, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f)); |
| sglr::drawQuad(ctx, colorShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(+0.5f, +0.5f, 0.0f)); |
| |
| // Draw metaballs with stencil test where stencil > 1 or 2 depending on depth buffer |
| ctx.bindTexture(GL_TEXTURE_2D, metaballsTex); |
| ctx.stencilFunc(GL_GREATER, depth ? 1 : 2, 0xffu); |
| ctx.stencilOp(GL_KEEP, GL_KEEP, GL_KEEP); |
| sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f)); |
| |
| ctx.disable(GL_STENCIL_TEST); |
| |
| if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D) |
| { |
| ctx.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| ctx.activeTexture(GL_TEXTURE0); |
| ctx.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer()); |
| ctx.viewport(0, 0, ctx.getWidth(), ctx.getHeight()); |
| sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| ctx.readPixels(dst, 0, 0, ctx.getWidth(), ctx.getHeight()); |
| } |
| else |
| ctx.readPixels(dst, 0, 0, width, height); |
| } |
| |
| class SharedColorbufferTest : public FboRenderCase |
| { |
| public: |
| SharedColorbufferTest (Context& context, const FboConfig& config); |
| virtual ~SharedColorbufferTest (void) {}; |
| |
| void render (sglr::Context& context, Surface& dst); |
| }; |
| |
| SharedColorbufferTest::SharedColorbufferTest (Context& context, const FboConfig& config) |
| : FboRenderCase(context, config.getName().c_str(), "Shared colorbuffer", config) |
| { |
| } |
| |
| void SharedColorbufferTest::render (sglr::Context& context, Surface& dst) |
| { |
| SingleTex2DShader shader; |
| deUint32 shaderID = context.createProgram(&shader); |
| int width = 128; |
| int height = 128; |
| // bool depth = getConfig().depthbufferFormat != GL_NONE; |
| bool stencil = getConfig().stencilbufferFormat != GL_NONE; |
| |
| // Textures |
| deUint32 quadsTex = 1; |
| deUint32 metaballsTex = 2; |
| createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64); |
| createMetaballsTex2D(context, metaballsTex, GL_RGBA, GL_UNSIGNED_BYTE, 64, 64); |
| |
| context.viewport(0, 0, width, height); |
| |
| shader.setUnit(context, shaderID, 0); |
| |
| // Fbo A |
| Framebuffer fboA(context, getConfig(), width, height); |
| fboA.checkCompleteness(); |
| |
| // Fbo B - don't create colorbuffer |
| FboConfig cfg = getConfig(); |
| cfg.colorbufferType = GL_NONE; |
| cfg.colorbufferFormat = GL_NONE; |
| Framebuffer fboB(context, cfg, width, height); |
| |
| // Attach color buffer from fbo A |
| context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer()); |
| switch (getConfig().colorbufferType) |
| { |
| case GL_TEXTURE_2D: |
| context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboA.getColorbuffer(), 0); |
| break; |
| |
| case GL_RENDERBUFFER: |
| context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fboA.getColorbuffer()); |
| break; |
| |
| default: |
| DE_ASSERT(false); |
| } |
| |
| // Clear depth and stencil in fbo B |
| context.clear(GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| // Render quads to fbo 1, with depth 0.0 |
| context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer()); |
| context.bindTexture(GL_TEXTURE_2D, quadsTex); |
| context.clearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| if (stencil) |
| { |
| // Stencil to 1 in fbo A |
| context.clearStencil(1); |
| context.clear(GL_STENCIL_BUFFER_BIT); |
| } |
| |
| context.enable(GL_DEPTH_TEST); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| context.disable(GL_DEPTH_TEST); |
| |
| // Blend metaballs to fbo 2 |
| context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer()); |
| context.bindTexture(GL_TEXTURE_2D, metaballsTex); |
| context.enable(GL_BLEND); |
| context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| // Render small quad that is only visible if depth buffer is not shared with fbo A - or there is no depth bits |
| context.bindTexture(GL_TEXTURE_2D, quadsTex); |
| context.enable(GL_DEPTH_TEST); |
| sglr::drawQuad(context, shaderID, Vec3(0.5f, 0.5f, 0.5f), Vec3(1.0f, 1.0f, 0.5f)); |
| context.disable(GL_DEPTH_TEST); |
| |
| if (stencil) |
| { |
| FlatColorShader flatShader; |
| deUint32 flatShaderID = context.createProgram(&flatShader); |
| |
| flatShader.setColor(context, flatShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f)); |
| |
| // Clear subset of stencil buffer to 1 |
| context.enable(GL_SCISSOR_TEST); |
| context.scissor(10, 10, 12, 25); |
| context.clearStencil(1); |
| context.clear(GL_STENCIL_BUFFER_BIT); |
| context.disable(GL_SCISSOR_TEST); |
| |
| // Render quad with stencil mask == 1 |
| context.enable(GL_STENCIL_TEST); |
| context.stencilFunc(GL_EQUAL, 1, 0xffu); |
| sglr::drawQuad(context, flatShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| context.disable(GL_STENCIL_TEST); |
| } |
| |
| // Get results |
| if (fboA.getConfig().colorbufferType == GL_TEXTURE_2D) |
| { |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer()); |
| context.viewport(0, 0, context.getWidth(), context.getHeight()); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight()); |
| } |
| else |
| context.readPixels(dst, 0, 0, width, height); |
| } |
| |
| class SharedColorbufferClearsTest : public FboRenderCase |
| { |
| public: |
| SharedColorbufferClearsTest (Context& context, const FboConfig& config); |
| virtual ~SharedColorbufferClearsTest (void) {} |
| |
| static bool isConfigSupported (const FboConfig& config); |
| void render (sglr::Context& context, Surface& dst); |
| }; |
| |
| SharedColorbufferClearsTest::SharedColorbufferClearsTest (Context& context, const FboConfig& config) |
| : FboRenderCase(context, config.getName().c_str(), "Shared colorbuffer clears", config) |
| { |
| } |
| |
| bool SharedColorbufferClearsTest::isConfigSupported (const FboConfig& config) |
| { |
| return config.colorbufferType != GL_NONE && |
| config.depthbufferType == GL_NONE && |
| config.stencilbufferType == GL_NONE; |
| } |
| |
| void SharedColorbufferClearsTest::render (sglr::Context& context, Surface& dst) |
| { |
| int width = 128; |
| int height = 128; |
| deUint32 colorbuffer = 1; |
| |
| checkColorFormatSupport(context, getConfig().colorbufferFormat); |
| |
| // Single colorbuffer |
| if (getConfig().colorbufferType == GL_TEXTURE_2D) |
| { |
| context.bindTexture(GL_TEXTURE_2D, colorbuffer); |
| context.texImage2D(GL_TEXTURE_2D, 0, getConfig().colorbufferFormat, width, height); |
| context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| } |
| else |
| { |
| DE_ASSERT(getConfig().colorbufferType == GL_RENDERBUFFER); |
| context.bindRenderbuffer(GL_RENDERBUFFER, colorbuffer); |
| context.renderbufferStorage(GL_RENDERBUFFER, getConfig().colorbufferFormat, width, height); |
| } |
| |
| // Multiple framebuffers sharing the colorbuffer |
| for (int fbo = 1; fbo <= 3; fbo++) |
| { |
| context.bindFramebuffer(GL_FRAMEBUFFER, fbo); |
| |
| if (getConfig().colorbufferType == GL_TEXTURE_2D) |
| context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuffer, 0); |
| else |
| context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuffer); |
| } |
| |
| context.bindFramebuffer(GL_FRAMEBUFFER, 1); |
| |
| // Check completeness |
| { |
| GLenum status = context.checkFramebufferStatus(GL_FRAMEBUFFER); |
| if (status != GL_FRAMEBUFFER_COMPLETE) |
| throw FboIncompleteException(getConfig(), status, __FILE__, __LINE__); |
| } |
| |
| // Render to them |
| context.viewport(0, 0, width, height); |
| context.clearColor(0.0f, 0.0f, 1.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT); |
| |
| context.enable(GL_SCISSOR_TEST); |
| |
| context.bindFramebuffer(GL_FRAMEBUFFER, 2); |
| context.clearColor(0.6f, 0.0f, 0.0f, 1.0f); |
| context.scissor(10, 10, 64, 64); |
| context.clear(GL_COLOR_BUFFER_BIT); |
| context.clearColor(0.0f, 0.6f, 0.0f, 1.0f); |
| context.scissor(60, 60, 40, 20); |
| context.clear(GL_COLOR_BUFFER_BIT); |
| |
| context.bindFramebuffer(GL_FRAMEBUFFER, 3); |
| context.clearColor(0.0f, 0.0f, 0.6f, 1.0f); |
| context.scissor(20, 20, 100, 10); |
| context.clear(GL_COLOR_BUFFER_BIT); |
| |
| context.bindFramebuffer(GL_FRAMEBUFFER, 1); |
| context.clearColor(0.6f, 0.0f, 0.6f, 1.0f); |
| context.scissor(20, 20, 5, 100); |
| context.clear(GL_COLOR_BUFFER_BIT); |
| |
| context.disable(GL_SCISSOR_TEST); |
| |
| if (getConfig().colorbufferType == GL_TEXTURE_2D) |
| { |
| SingleTex2DShader shader; |
| deUint32 shaderID = context.createProgram(&shader); |
| |
| shader.setUnit(context, shaderID, 0); |
| |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| context.viewport(0, 0, context.getWidth(), context.getHeight()); |
| sglr::drawQuad(context, shaderID, Vec3(-0.9f, -0.9f, 0.0f), Vec3(0.9f, 0.9f, 0.0f)); |
| context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight()); |
| } |
| else |
| context.readPixels(dst, 0, 0, width, height); |
| } |
| |
| class SharedDepthbufferTest : public FboRenderCase |
| { |
| public: |
| SharedDepthbufferTest (Context& context, const FboConfig& config); |
| virtual ~SharedDepthbufferTest (void) {}; |
| |
| static bool isConfigSupported (const FboConfig& config); |
| void render (sglr::Context& context, Surface& dst); |
| }; |
| |
| SharedDepthbufferTest::SharedDepthbufferTest (Context& context, const FboConfig& config) |
| : FboRenderCase(context, config.getName().c_str(), "Shared depthbuffer", config) |
| { |
| } |
| |
| bool SharedDepthbufferTest::isConfigSupported (const FboConfig& config) |
| { |
| return config.depthbufferType == GL_RENDERBUFFER; |
| } |
| |
| void SharedDepthbufferTest::render (sglr::Context& context, Surface& dst) |
| { |
| SingleTex2DShader texShader; |
| FlatColorShader colorShader; |
| deUint32 texShaderID = context.createProgram(&texShader); |
| deUint32 colorShaderID = context.createProgram(&colorShader); |
| int width = 128; |
| int height = 128; |
| bool stencil = getConfig().stencilbufferType != GL_NONE; |
| |
| // Setup shaders |
| texShader.setUnit(context, texShaderID, 0); |
| colorShader.setColor(context, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f)); |
| |
| // Textures |
| deUint32 metaballsTex = 5; |
| deUint32 quadsTex = 6; |
| createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64); |
| createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64); |
| |
| context.viewport(0, 0, width, height); |
| |
| // Fbo A |
| Framebuffer fboA(context, getConfig(), width, height); |
| fboA.checkCompleteness(); |
| |
| // Fbo B |
| FboConfig cfg = getConfig(); |
| cfg.depthbufferType = GL_NONE; |
| cfg.depthbufferFormat = GL_NONE; |
| Framebuffer fboB(context, cfg, width, height); |
| |
| // Bind depth buffer from fbo A to fbo B |
| DE_ASSERT(fboA.getConfig().depthbufferType == GL_RENDERBUFFER); |
| context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer()); |
| context.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fboA.getDepthbuffer()); |
| |
| // Clear fbo B color to red and stencil to 1 |
| context.clearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| context.clearStencil(1); |
| context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| // Enable depth test. |
| context.enable(GL_DEPTH_TEST); |
| |
| // Render quad to fbo A |
| context.bindFramebuffer(GL_FRAMEBUFFER, fboA.getFramebuffer()); |
| context.bindTexture(GL_TEXTURE_2D, quadsTex); |
| context.clearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| // Render metaballs to fbo B |
| context.bindFramebuffer(GL_FRAMEBUFFER, fboB.getFramebuffer()); |
| context.bindTexture(GL_TEXTURE_2D, metaballsTex); |
| sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, -1.0f), Vec3(1.0f, 1.0f, 1.0f)); |
| |
| context.disable(GL_DEPTH_TEST); |
| |
| if (stencil) |
| { |
| // Clear subset of stencil buffer to 0 |
| context.enable(GL_SCISSOR_TEST); |
| context.scissor(10, 10, 12, 25); |
| context.clearStencil(0); |
| context.clear(GL_STENCIL_BUFFER_BIT); |
| context.disable(GL_SCISSOR_TEST); |
| |
| // Render quad with stencil mask == 0 |
| context.enable(GL_STENCIL_TEST); |
| context.stencilFunc(GL_EQUAL, 0, 0xffu); |
| sglr::drawQuad(context, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| context.disable(GL_STENCIL_TEST); |
| } |
| |
| if (getConfig().colorbufferType == GL_TEXTURE_2D) |
| { |
| // Render both to screen |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| context.viewport(0, 0, context.getWidth(), context.getHeight()); |
| context.bindTexture(GL_TEXTURE_2D, fboA.getColorbuffer()); |
| sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(0.0f, 1.0f, 0.0f)); |
| context.bindTexture(GL_TEXTURE_2D, fboB.getColorbuffer()); |
| sglr::drawQuad(context, texShaderID, Vec3(0.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight()); |
| } |
| else |
| { |
| // Read results from fbo B |
| context.readPixels(dst, 0, 0, width, height); |
| } |
| } |
| |
| class TexSubImageAfterRenderTest : public FboRenderCase |
| { |
| public: |
| TexSubImageAfterRenderTest (Context& context, const FboConfig& config); |
| virtual ~TexSubImageAfterRenderTest (void) {} |
| |
| static bool isConfigSupported (const FboConfig& config); |
| void render (sglr::Context& context, Surface& dst); |
| }; |
| |
| TexSubImageAfterRenderTest::TexSubImageAfterRenderTest (Context& context, const FboConfig& config) |
| : FboRenderCase(context, (string("after_render_") + config.getName()).c_str(), "TexSubImage after rendering to texture", config) |
| { |
| } |
| |
| bool TexSubImageAfterRenderTest::isConfigSupported (const FboConfig& config) |
| { |
| return config.colorbufferType == GL_TEXTURE_2D && |
| (config.colorbufferFormat == GL_RGB || config.colorbufferFormat == GL_RGBA) && |
| config.depthbufferType == GL_NONE && |
| config.stencilbufferType == GL_NONE; |
| } |
| |
| void TexSubImageAfterRenderTest::render (sglr::Context& context, Surface& dst) |
| { |
| SingleTex2DShader shader; |
| deUint32 shaderID = context.createProgram(&shader); |
| bool isRGBA = getConfig().colorbufferFormat == GL_RGBA; |
| |
| tcu::TextureLevel fourQuads(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64); |
| tcu::fillWithRGBAQuads(fourQuads.getAccess()); |
| |
| tcu::TextureLevel metaballs(tcu::TextureFormat(isRGBA ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64); |
| tcu::fillWithMetaballs(metaballs.getAccess(), 5, 3); |
| |
| shader.setUnit(context, shaderID, 0); |
| |
| deUint32 fourQuadsTex = 1; |
| context.bindTexture(GL_TEXTURE_2D, fourQuadsTex); |
| context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| context.texImage2D(GL_TEXTURE_2D, 0, GL_RGB, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, fourQuads.getAccess().getDataPtr()); |
| |
| context.bindFramebuffer(GL_FRAMEBUFFER, 1); |
| |
| deUint32 fboTex = 2; |
| context.bindTexture(GL_TEXTURE_2D, fboTex); |
| context.texImage2D(GL_TEXTURE_2D, 0, isRGBA ? GL_RGBA : GL_RGB, 128, 128); |
| context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0); |
| |
| // Render to fbo |
| context.viewport(0, 0, 128, 128); |
| context.bindTexture(GL_TEXTURE_2D, fourQuadsTex); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| // Update texture using TexSubImage2D |
| context.bindTexture(GL_TEXTURE_2D, fboTex); |
| context.texSubImage2D(GL_TEXTURE_2D, 0, 32, 32, 64, 64, isRGBA ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, metaballs.getAccess().getDataPtr()); |
| |
| // Draw to screen |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| context.viewport(0, 0, context.getWidth(), context.getHeight()); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight()); |
| } |
| |
| class TexSubImageBetweenRenderTest : public FboRenderCase |
| { |
| public: |
| TexSubImageBetweenRenderTest (Context& context, const FboConfig& config); |
| virtual ~TexSubImageBetweenRenderTest (void) {} |
| |
| static bool isConfigSupported (const FboConfig& config); |
| void render (sglr::Context& context, Surface& dst); |
| }; |
| |
| TexSubImageBetweenRenderTest::TexSubImageBetweenRenderTest (Context& context, const FboConfig& config) |
| : FboRenderCase(context, (string("between_render_") + config.getName()).c_str(), "TexSubImage between rendering calls", config) |
| { |
| } |
| |
| bool TexSubImageBetweenRenderTest::isConfigSupported (const FboConfig& config) |
| { |
| return config.colorbufferType == GL_TEXTURE_2D && |
| (config.colorbufferFormat == GL_RGB || config.colorbufferFormat == GL_RGBA) && |
| config.depthbufferType == GL_NONE && |
| config.stencilbufferType == GL_NONE; |
| } |
| |
| void TexSubImageBetweenRenderTest::render (sglr::Context& context, Surface& dst) |
| { |
| SingleTex2DShader shader; |
| deUint32 shaderID = context.createProgram(&shader); |
| bool isRGBA = getConfig().colorbufferFormat == GL_RGBA; |
| |
| tcu::TextureLevel fourQuads(tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64); |
| tcu::fillWithRGBAQuads(fourQuads.getAccess()); |
| |
| tcu::TextureLevel metaballs(tcu::TextureFormat(isRGBA ? tcu::TextureFormat::RGBA : tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8), 64, 64); |
| tcu::fillWithMetaballs(metaballs.getAccess(), 5, 3); |
| |
| tcu::TextureLevel metaballs2(tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 64, 64); |
| tcu::fillWithMetaballs(metaballs2.getAccess(), 5, 4); |
| |
| deUint32 metaballsTex = 3; |
| context.bindTexture(GL_TEXTURE_2D, metaballsTex); |
| context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| context.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, metaballs2.getAccess().getDataPtr()); |
| |
| deUint32 fourQuadsTex = 1; |
| context.bindTexture(GL_TEXTURE_2D, fourQuadsTex); |
| context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| context.texImage2D(GL_TEXTURE_2D, 0, GL_RGB, 64, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, fourQuads.getAccess().getDataPtr()); |
| |
| context.bindFramebuffer(GL_FRAMEBUFFER, 1); |
| |
| deUint32 fboTex = 2; |
| context.bindTexture(GL_TEXTURE_2D, fboTex); |
| context.texImage2D(GL_TEXTURE_2D, 0, isRGBA ? GL_RGBA : GL_RGB, 128, 128); |
| context.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| context.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0); |
| |
| shader.setUnit(context, shaderID, 0); |
| |
| // Render to fbo |
| context.viewport(0, 0, 128, 128); |
| context.bindTexture(GL_TEXTURE_2D, fourQuadsTex); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| // Update texture using TexSubImage2D |
| context.bindTexture(GL_TEXTURE_2D, fboTex); |
| context.texSubImage2D(GL_TEXTURE_2D, 0, 32, 32, 64, 64, isRGBA ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, metaballs.getAccess().getDataPtr()); |
| |
| // Render again to fbo |
| context.bindTexture(GL_TEXTURE_2D, metaballsTex); |
| context.enable(GL_BLEND); |
| context.blendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| context.disable(GL_BLEND); |
| |
| // Draw to screen |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| context.viewport(0, 0, context.getWidth(), context.getHeight()); |
| context.bindTexture(GL_TEXTURE_2D, fboTex); |
| sglr::drawQuad(context, shaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight()); |
| } |
| |
| class ResizeTest : public FboRenderCase |
| { |
| public: |
| ResizeTest (Context& context, const FboConfig& config); |
| virtual ~ResizeTest (void) {} |
| |
| void render (sglr::Context& context, Surface& dst); |
| }; |
| |
| ResizeTest::ResizeTest (Context& context, const FboConfig& config) |
| : FboRenderCase(context, config.getName().c_str(), "Resize framebuffer", config) |
| { |
| } |
| |
| void ResizeTest::render (sglr::Context& context, Surface& dst) |
| { |
| SingleTex2DShader texShader; |
| FlatColorShader colorShader; |
| deUint32 texShaderID = context.createProgram(&texShader); |
| deUint32 colorShaderID = context.createProgram(&colorShader); |
| deUint32 quadsTex = 1; |
| deUint32 metaballsTex = 2; |
| bool depth = getConfig().depthbufferType != GL_NONE; |
| bool stencil = getConfig().stencilbufferType != GL_NONE; |
| |
| createQuadsTex2D(context, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64); |
| createMetaballsTex2D(context, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 32, 32); |
| |
| Framebuffer fbo(context, getConfig(), 128, 128); |
| fbo.checkCompleteness(); |
| |
| // Setup shaders |
| texShader.setUnit(context, texShaderID, 0); |
| colorShader.setColor(context, colorShaderID, Vec4(0.0f, 1.0f, 0.0f, 1.0f)); |
| |
| // Render quads |
| context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer()); |
| context.viewport(0, 0, 128, 128); |
| context.clearColor(0.0f, 0.0f, 0.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| context.bindTexture(GL_TEXTURE_2D, quadsTex); |
| sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| if (fbo.getConfig().colorbufferType == GL_TEXTURE_2D) |
| { |
| // Render fbo to screen |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| context.viewport(0, 0, context.getWidth(), context.getHeight()); |
| context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer()); |
| sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| // Restore binding |
| context.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer()); |
| } |
| |
| int newWidth = 64; |
| int newHeight = 32; |
| |
| // Resize buffers |
| switch (fbo.getConfig().colorbufferType) |
| { |
| case GL_TEXTURE_2D: |
| context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer()); |
| context.texImage2D(GL_TEXTURE_2D, 0, fbo.getConfig().colorbufferFormat, newWidth, newHeight); |
| break; |
| |
| case GL_RENDERBUFFER: |
| context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getColorbuffer()); |
| context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().colorbufferFormat, newWidth, newHeight); |
| break; |
| |
| default: |
| DE_ASSERT(false); |
| } |
| |
| if (depth) |
| { |
| DE_ASSERT(fbo.getConfig().depthbufferType == GL_RENDERBUFFER); |
| context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getDepthbuffer()); |
| context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().depthbufferFormat, newWidth, newHeight); |
| } |
| |
| if (stencil) |
| { |
| DE_ASSERT(fbo.getConfig().stencilbufferType == GL_RENDERBUFFER); |
| context.bindRenderbuffer(GL_RENDERBUFFER, fbo.getStencilbuffer()); |
| context.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().stencilbufferFormat, newWidth, newHeight); |
| } |
| |
| // Render to resized fbo |
| context.viewport(0, 0, newWidth, newHeight); |
| context.clearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| context.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| context.enable(GL_DEPTH_TEST); |
| |
| context.bindTexture(GL_TEXTURE_2D, metaballsTex); |
| sglr::drawQuad(context, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f)); |
| |
| context.bindTexture(GL_TEXTURE_2D, quadsTex); |
| sglr::drawQuad(context, texShaderID, Vec3(0.0f, 0.0f, -1.0f), Vec3(+1.0f, +1.0f, 1.0f)); |
| |
| context.disable(GL_DEPTH_TEST); |
| |
| if (stencil) |
| { |
| context.enable(GL_SCISSOR_TEST); |
| context.scissor(10, 10, 5, 15); |
| context.clearStencil(1); |
| context.clear(GL_STENCIL_BUFFER_BIT); |
| context.disable(GL_SCISSOR_TEST); |
| |
| context.enable(GL_STENCIL_TEST); |
| context.stencilFunc(GL_EQUAL, 1, 0xffu); |
| sglr::drawQuad(context, colorShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(+1.0f, +1.0f, 0.0f)); |
| context.disable(GL_STENCIL_TEST); |
| } |
| |
| if (getConfig().colorbufferType == GL_TEXTURE_2D) |
| { |
| context.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| context.viewport(0, 0, context.getWidth(), context.getHeight()); |
| context.bindTexture(GL_TEXTURE_2D, fbo.getColorbuffer()); |
| sglr::drawQuad(context, texShaderID, Vec3(-0.5f, -0.5f, 0.0f), Vec3(0.5f, 0.5f, 0.0f)); |
| context.readPixels(dst, 0, 0, context.getWidth(), context.getHeight()); |
| } |
| else |
| context.readPixels(dst, 0, 0, newWidth, newHeight); |
| } |
| |
| template <GLenum Buffers> |
| class RecreateBuffersTest : public FboRenderCase |
| { |
| public: |
| RecreateBuffersTest (Context& context, const FboConfig& config, bool rebind); |
| virtual ~RecreateBuffersTest (void) {} |
| |
| static bool isConfigSupported (const FboConfig& config); |
| void render (sglr::Context& context, Surface& dst); |
| |
| private: |
| bool m_rebind; |
| }; |
| |
| template <GLenum Buffers> |
| class RecreateBuffersNoRebindTest : public RecreateBuffersTest<Buffers> |
| { |
| public: |
| RecreateBuffersNoRebindTest (Context& context, const FboConfig& config) |
| : RecreateBuffersTest<Buffers>(context, config, false) |
| { |
| } |
| }; |
| |
| template <GLenum Buffers> |
| class RecreateBuffersRebindTest : public RecreateBuffersTest<Buffers> |
| { |
| public: |
| RecreateBuffersRebindTest (Context& context, const FboConfig& config) |
| : RecreateBuffersTest<Buffers>(context, config, true) |
| { |
| } |
| }; |
| |
| template <GLenum Buffers> |
| RecreateBuffersTest<Buffers>::RecreateBuffersTest (Context& context, const FboConfig& config, bool rebind) |
| : FboRenderCase (context, (string(rebind ? "rebind_" : "no_rebind_") + config.getName()).c_str(), "Recreate buffers", config) |
| , m_rebind (rebind) |
| { |
| } |
| |
| template <GLenum Buffers> |
| bool RecreateBuffersTest<Buffers>::isConfigSupported (const FboConfig& config) |
| { |
| if ((Buffers & GL_COLOR_BUFFER_BIT) && config.colorbufferType == GL_NONE) |
| return false; |
| if ((Buffers & GL_DEPTH_BUFFER_BIT) && config.depthbufferType == GL_NONE) |
| return false; |
| if ((Buffers & GL_STENCIL_BUFFER_BIT) && config.stencilbufferType == GL_NONE) |
| return false; |
| return true; |
| } |
| |
| template <GLenum Buffers> |
| void RecreateBuffersTest<Buffers>::render (sglr::Context& ctx, Surface& dst) |
| { |
| SingleTex2DShader texShader; |
| deUint32 texShaderID = ctx.createProgram(&texShader); |
| int width = 128; |
| int height = 128; |
| deUint32 metaballsTex = 1; |
| deUint32 quadsTex = 2; |
| bool stencil = getConfig().stencilbufferType != GL_NONE; |
| |
| createQuadsTex2D(ctx, quadsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64); |
| createMetaballsTex2D(ctx, metaballsTex, GL_RGB, GL_UNSIGNED_BYTE, 64, 64); |
| |
| Framebuffer fbo(ctx, getConfig(), width, height); |
| fbo.checkCompleteness(); |
| |
| // Setup shader |
| texShader.setUnit(ctx, texShaderID, 0); |
| |
| // Draw scene |
| ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer()); |
| ctx.viewport(0, 0, width, height); |
| ctx.clearColor(1.0f, 0.0f, 0.0f, 1.0f); |
| ctx.clear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); |
| |
| ctx.enable(GL_DEPTH_TEST); |
| |
| ctx.bindTexture(GL_TEXTURE_2D, quadsTex); |
| sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| |
| if (stencil) |
| { |
| ctx.enable(GL_SCISSOR_TEST); |
| ctx.scissor(width/4, height/4, width/2, height/2); |
| ctx.clearStencil(1); |
| ctx.clear(GL_STENCIL_BUFFER_BIT); |
| ctx.disable(GL_SCISSOR_TEST); |
| } |
| |
| // Recreate buffers |
| if (!m_rebind) |
| ctx.bindFramebuffer(GL_FRAMEBUFFER, 0); |
| |
| if (Buffers & GL_COLOR_BUFFER_BIT) |
| { |
| deUint32 colorbuf = fbo.getColorbuffer(); |
| switch (fbo.getConfig().colorbufferType) |
| { |
| case GL_TEXTURE_2D: |
| ctx.deleteTextures(1, &colorbuf); |
| ctx.bindTexture(GL_TEXTURE_2D, colorbuf); |
| ctx.texImage2D(GL_TEXTURE_2D, 0, fbo.getConfig().colorbufferFormat, width, height); |
| ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| |
| if (m_rebind) |
| ctx.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorbuf, 0); |
| break; |
| |
| case GL_RENDERBUFFER: |
| ctx.deleteRenderbuffers(1, &colorbuf); |
| ctx.bindRenderbuffer(GL_RENDERBUFFER, colorbuf); |
| ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().colorbufferFormat, width, height); |
| |
| if (m_rebind) |
| ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorbuf); |
| break; |
| |
| default: |
| DE_ASSERT(false); |
| } |
| } |
| |
| if (Buffers & GL_DEPTH_BUFFER_BIT) |
| { |
| deUint32 depthbuf = fbo.getDepthbuffer(); |
| DE_ASSERT(fbo.getConfig().depthbufferType == GL_RENDERBUFFER); |
| |
| ctx.deleteRenderbuffers(1, &depthbuf); |
| ctx.bindRenderbuffer(GL_RENDERBUFFER, depthbuf); |
| ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().depthbufferFormat, width, height); |
| |
| if (m_rebind) |
| ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthbuf); |
| } |
| |
| if (Buffers & GL_STENCIL_BUFFER_BIT) |
| { |
| deUint32 stencilbuf = fbo.getStencilbuffer(); |
| DE_ASSERT(fbo.getConfig().stencilbufferType == GL_RENDERBUFFER); |
| |
| ctx.deleteRenderbuffers(1, &stencilbuf); |
| ctx.bindRenderbuffer(GL_RENDERBUFFER, stencilbuf); |
| ctx.renderbufferStorage(GL_RENDERBUFFER, fbo.getConfig().stencilbufferFormat, width, height); |
| |
| if (m_rebind) |
| ctx.framebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilbuf); |
| } |
| |
| if (!m_rebind) |
| ctx.bindFramebuffer(GL_FRAMEBUFFER, fbo.getFramebuffer()); |
| |
| ctx.clearColor(0.0f, 0.0f, 1.0f, 0.0f); |
| ctx.clearStencil(0); |
| ctx.clear(Buffers); // \note Clear only buffers that were re-created |
| |
| if (stencil) |
| { |
| // \note Stencil test enabled only if we have stencil buffer |
| ctx.enable(GL_STENCIL_TEST); |
| ctx.stencilFunc(GL_EQUAL, 0, 0xffu); |
| } |
| ctx.bindTexture(GL_TEXTURE_2D, metaballsTex); |
| sglr::drawQuad(ctx, texShaderID, Vec3(-1.0f, -1.0f, 1.0f), Vec3(1.0f, 1.0f, -1.0f)); |
| if (stencil) |
| ctx.disable(GL_STENCIL_TEST); |
| |
| ctx.disable(GL_DEPTH_TEST); |
| |
| // Read from fbo |
| ctx.readPixels(dst, 0, 0, width, height); |
| } |
| |
| class RepeatedClearCase : public FboRenderCase |
| { |
| private: |
| static FboConfig makeConfig (deUint32 format) |
| { |
| FboConfig cfg; |
| cfg.colorbufferType = GL_TEXTURE_2D; |
| cfg.colorbufferFormat = format; |
| cfg.depthbufferType = GL_NONE; |
| cfg.stencilbufferType = GL_NONE; |
| return cfg; |
| } |
| |
| public: |
| RepeatedClearCase (Context& context, deUint32 format) |
| : FboRenderCase(context, makeConfig(format).getName().c_str(), "Repeated clears", makeConfig(format)) |
| { |
| } |
| |
| protected: |
| void render (sglr::Context& ctx, Surface& dst) |
| { |
| const int numRowsCols = 4; |
| const int cellSize = 16; |
| const int fboSizes[] = { cellSize, cellSize*numRowsCols }; |
| |
| SingleTex2DShader fboBlitShader; |
| const deUint32 fboBlitShaderID = ctx.createProgram(&fboBlitShader); |
| |
| de::Random rnd (18169662); |
| deUint32 fbos[] = { 0, 0 }; |
| deUint32 textures[] = { 0, 0 }; |
| |
| ctx.genFramebuffers(2, &fbos[0]); |
| ctx.genTextures(2, &textures[0]); |
| |
| for (int fboNdx = 0; fboNdx < DE_LENGTH_OF_ARRAY(fbos); fboNdx++) |
| { |
| ctx.bindTexture(GL_TEXTURE_2D, textures[fboNdx]); |
| ctx.texImage2D(GL_TEXTURE_2D, 0, getConfig().colorbufferFormat, fboSizes[fboNdx], fboSizes[fboNdx], 0, |
| getConfig().colorbufferFormat, GL_UNSIGNED_BYTE, DE_NULL); |
| ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| ctx.texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| |
| ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[fboNdx]); |
| ctx.framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textures[fboNdx], 0); |
| |
| { |
| const GLenum status = ctx.checkFramebufferStatus(GL_FRAMEBUFFER); |
| if (status != GL_FRAMEBUFFER_COMPLETE) |
| throw FboIncompleteException(getConfig(), status, __FILE__, __LINE__); |
| } |
| } |
| |
| // larger fbo bound -- clear to transparent black |
| ctx.clearColor(0.0f, 0.0f, 0.0f, 0.0f); |
| ctx.clear(GL_COLOR_BUFFER_BIT); |
| |
| fboBlitShader.setUnit(ctx, fboBlitShaderID, 0); |
| ctx.bindTexture(GL_TEXTURE_2D, textures[0]); |
| |
| for (int cellY = 0; cellY < numRowsCols; cellY++) |
| for (int cellX = 0; cellX < numRowsCols; cellX++) |
| { |
| const float r = rnd.getFloat(); |
| const float g = rnd.getFloat(); |
| const float b = rnd.getFloat(); |
| const float a = rnd.getFloat(); |
| |
| ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[0]); |
| ctx.clearColor(r, g, b, a); |
| ctx.clear(GL_COLOR_BUFFER_BIT); |
| |
| ctx.bindFramebuffer(GL_FRAMEBUFFER, fbos[1]); |
| ctx.viewport(cellX*cellSize, cellY*cellSize, cellSize, cellSize); |
| sglr::drawQuad(ctx, fboBlitShaderID, Vec3(-1.0f, -1.0f, 0.0f), Vec3(1.0f, 1.0f, 0.0f)); |
| } |
| |
| ctx.readPixels(dst, 0, 0, fboSizes[1], fboSizes[1]); |
| } |
| }; |
| |
| } // FboCases |
| |
| FboRenderTestGroup::FboRenderTestGroup (Context& context) |
| : TestCaseGroup(context, "render", "Rendering Tests") |
| { |
| } |
| |
| FboRenderTestGroup::~FboRenderTestGroup (void) |
| { |
| } |
| |
| namespace |
| { |
| |
| struct TypeFormatPair |
| { |
| GLenum type; |
| GLenum format; |
| }; |
| |
| template <typename CaseType> |
| void addChildVariants (deqp::gles2::TestCaseGroup* group) |
| { |
| TypeFormatPair colorbufferConfigs[] = |
| { |
| // { GL_TEXTURE_2D, GL_ALPHA }, |
| // { GL_TEXTURE_2D, GL_LUMINANCE }, |
| // { GL_TEXTURE_2D, GL_LUMINANCE_ALPHA }, |
| { GL_TEXTURE_2D, GL_RGB }, |
| { GL_TEXTURE_2D, GL_RGBA }, |
| { GL_RENDERBUFFER, GL_RGB565 }, |
| { GL_RENDERBUFFER, GL_RGB5_A1 }, |
| { GL_RENDERBUFFER, GL_RGBA4 }, |
| // { GL_RENDERBUFFER, GL_RGBA16F }, |
| // { GL_RENDERBUFFER, GL_RGB16F } |
| }; |
| TypeFormatPair depthbufferConfigs[] = |
| { |
| { GL_NONE, GL_NONE }, |
| { GL_RENDERBUFFER, GL_DEPTH_COMPONENT16 } |
| }; |
| TypeFormatPair stencilbufferConfigs[] = |
| { |
| { GL_NONE, GL_NONE }, |
| { GL_RENDERBUFFER, GL_STENCIL_INDEX8 } |
| }; |
| |
| for (int colorbufferNdx = 0; colorbufferNdx < DE_LENGTH_OF_ARRAY(colorbufferConfigs); colorbufferNdx++) |
| for (int depthbufferNdx = 0; depthbufferNdx < DE_LENGTH_OF_ARRAY(depthbufferConfigs); depthbufferNdx++) |
| for (int stencilbufferNdx = 0; stencilbufferNdx < DE_LENGTH_OF_ARRAY(stencilbufferConfigs); stencilbufferNdx++) |
| { |
| FboConfig config; |
| config.colorbufferType = colorbufferConfigs[colorbufferNdx].type; |
| config.colorbufferFormat = colorbufferConfigs[colorbufferNdx].format; |
| config.depthbufferType = depthbufferConfigs[depthbufferNdx].type; |
| config.depthbufferFormat = depthbufferConfigs[depthbufferNdx].format; |
| config.stencilbufferType = stencilbufferConfigs[stencilbufferNdx].type; |
| config.stencilbufferFormat = stencilbufferConfigs[stencilbufferNdx].format; |
| |
| if (CaseType::isConfigSupported(config)) |
| group->addChild(new CaseType(group->getContext(), config)); |
| } |
| } |
| |
| template <typename CaseType> |
| void createChildGroup (deqp::gles2::TestCaseGroup* parent, const char* name, const char* description) |
| { |
| deqp::gles2::TestCaseGroup* tmpGroup = new deqp::gles2::TestCaseGroup(parent->getContext(), name, description); |
| parent->addChild(tmpGroup); |
| addChildVariants<CaseType>(tmpGroup); |
| } |
| |
| template <GLbitfield Buffers> |
| void createRecreateBuffersGroup (deqp::gles2::TestCaseGroup* parent, const char* name, const char* description) |
| { |
| deqp::gles2::TestCaseGroup* tmpGroup = new deqp::gles2::TestCaseGroup(parent->getContext(), name, description); |
| parent->addChild(tmpGroup); |
| addChildVariants<FboCases::RecreateBuffersRebindTest<Buffers> > (tmpGroup); |
| addChildVariants<FboCases::RecreateBuffersNoRebindTest<Buffers> > (tmpGroup); |
| } |
| |
| } // anonymous |
| |
| void FboRenderTestGroup::init (void) |
| { |
| createChildGroup<FboCases::ColorClearsTest> (this, "color_clear", "Color buffer clears"); |
| createChildGroup<FboCases::StencilClearsTest> (this, "stencil_clear", "Stencil buffer clears"); |
| |
| deqp::gles2::TestCaseGroup* colorGroup = new deqp::gles2::TestCaseGroup(m_context, "color", "Color buffer tests"); |
| addChild(colorGroup); |
| addChildVariants<FboCases::MixTest> (colorGroup); |
| addChildVariants<FboCases::MixNpotTest> (colorGroup); |
| addChildVariants<FboCases::BlendTest> (colorGroup); |
| addChildVariants<FboCases::BlendNpotTest> (colorGroup); |
| |
| deqp::gles2::TestCaseGroup* depthGroup = new deqp::gles2::TestCaseGroup(m_context, "depth", "Depth bufer tests"); |
| addChild(depthGroup); |
| addChildVariants<FboCases::IntersectingQuadsTest> (depthGroup); |
| addChildVariants<FboCases::IntersectingQuadsNpotTest> (depthGroup); |
| |
| deqp::gles2::TestCaseGroup* stencilGroup = new deqp::gles2::TestCaseGroup(m_context, "stencil", "Stencil buffer tests"); |
| addChild(stencilGroup); |
| addChildVariants<FboCases::StencilTest> (stencilGroup); |
| addChildVariants<FboCases::StencilNpotTest> (stencilGroup); |
| |
| createChildGroup<FboCases::SharedColorbufferClearsTest> (this, "shared_colorbuffer_clear", "Shared colorbuffer clears"); |
| createChildGroup<FboCases::SharedColorbufferTest> (this, "shared_colorbuffer", "Shared colorbuffer tests"); |
| createChildGroup<FboCases::SharedDepthbufferTest> (this, "shared_depthbuffer", "Shared depthbuffer tests"); |
| createChildGroup<FboCases::ResizeTest> (this, "resize", "FBO resize tests"); |
| |
| createRecreateBuffersGroup<GL_COLOR_BUFFER_BIT> (this, "recreate_colorbuffer", "Recreate colorbuffer tests"); |
| createRecreateBuffersGroup<GL_DEPTH_BUFFER_BIT> (this, "recreate_depthbuffer", "Recreate depthbuffer tests"); |
| createRecreateBuffersGroup<GL_STENCIL_BUFFER_BIT> (this, "recreate_stencilbuffer", "Recreate stencilbuffer tests"); |
| |
| deqp::gles2::TestCaseGroup* texSubImageGroup = new deqp::gles2::TestCaseGroup(m_context, "texsubimage", "TexSubImage interop with FBO colorbuffer texture"); |
| addChild(texSubImageGroup); |
| addChildVariants<FboCases::TexSubImageAfterRenderTest> (texSubImageGroup); |
| addChildVariants<FboCases::TexSubImageBetweenRenderTest> (texSubImageGroup); |
| |
| { |
| tcu::TestCaseGroup* const repeatedClearGroup = new tcu::TestCaseGroup(m_testCtx, "repeated_clear", "Repeated FBO clears"); |
| addChild(repeatedClearGroup); |
| |
| repeatedClearGroup->addChild(new FboCases::RepeatedClearCase(m_context, GL_RGB)); |
| repeatedClearGroup->addChild(new FboCases::RepeatedClearCase(m_context, GL_RGBA)); |
| } |
| } |
| |
| } // Functional |
| } // gles2 |
| } // deqp |