| /*------------------------------------------------------------------------- |
| * drawElements Quality Program OpenGL ES Utilities |
| * ------------------------------------------------ |
| * |
| * 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 Reference Rendering Context. |
| *//*--------------------------------------------------------------------*/ |
| |
| #include "sglrReferenceContext.hpp" |
| #include "sglrReferenceUtils.hpp" |
| #include "sglrShaderProgram.hpp" |
| #include "tcuTextureUtil.hpp" |
| #include "tcuMatrix.hpp" |
| #include "tcuMatrixUtil.hpp" |
| #include "tcuVectorUtil.hpp" |
| #include "gluDefs.hpp" |
| #include "gluTextureUtil.hpp" |
| #include "glwFunctions.hpp" |
| #include "glwEnums.hpp" |
| #include "deMemory.h" |
| #include "rrFragmentOperations.hpp" |
| #include "rrRenderer.hpp" |
| |
| namespace sglr |
| { |
| |
| using std::vector; |
| using std::map; |
| |
| using tcu::Vec2; |
| using tcu::Vec3; |
| using tcu::Vec4; |
| using tcu::IVec2; |
| using tcu::IVec4; |
| using tcu::RGBA; |
| |
| // Reference context implementation |
| using namespace rc; |
| |
| using tcu::TextureFormat; |
| using tcu::PixelBufferAccess; |
| using tcu::ConstPixelBufferAccess; |
| |
| // Utilities for ReferenceContext |
| #define RC_RET_VOID |
| |
| #define RC_ERROR_RET(ERR, RET) \ |
| do { \ |
| setError(ERR); \ |
| return RET; \ |
| } while (deGetFalse()) |
| |
| #define RC_IF_ERROR(COND, ERR, RET) \ |
| do { \ |
| if (COND) \ |
| RC_ERROR_RET(ERR, RET); \ |
| } while (deGetFalse()) |
| |
| static inline tcu::PixelBufferAccess nullAccess (void) |
| { |
| return tcu::PixelBufferAccess(TextureFormat(TextureFormat::R, TextureFormat::UNSIGNED_INT8), 0, 0, 0, DE_NULL); |
| } |
| |
| static inline bool isEmpty (const tcu::ConstPixelBufferAccess& access) |
| { |
| return access.getWidth() == 0 || access.getHeight() == 0 || access.getDepth() == 0; |
| } |
| |
| static inline bool isEmpty (const rr::MultisampleConstPixelBufferAccess& access) |
| { |
| return access.raw().getWidth() == 0 || access.raw().getHeight() == 0 || access.raw().getDepth() == 0; |
| } |
| |
| static inline bool isEmpty (const IVec4& rect) |
| { |
| return rect.z() == 0 || rect.w() == 0; |
| } |
| |
| inline int getNumMipLevels1D (int size) |
| { |
| return deLog2Floor32(size)+1; |
| } |
| |
| inline int getNumMipLevels2D (int width, int height) |
| { |
| return deLog2Floor32(de::max(width, height))+1; |
| } |
| |
| inline int getNumMipLevels3D (int width, int height, int depth) |
| { |
| return deLog2Floor32(de::max(width, de::max(height, depth)))+1; |
| } |
| |
| inline int getMipLevelSize (int baseLevelSize, int levelNdx) |
| { |
| return de::max(baseLevelSize >> levelNdx, 1); |
| } |
| |
| inline bool isMipmapFilter (const tcu::Sampler::FilterMode mode) |
| { |
| return mode != tcu::Sampler::NEAREST && mode != tcu::Sampler::LINEAR; |
| } |
| |
| static tcu::CubeFace texTargetToFace (Framebuffer::TexTarget target) |
| { |
| switch (target) |
| { |
| case Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_X: return tcu::CUBEFACE_NEGATIVE_X; |
| case Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_X: return tcu::CUBEFACE_POSITIVE_X; |
| case Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Y: return tcu::CUBEFACE_NEGATIVE_Y; |
| case Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_Y: return tcu::CUBEFACE_POSITIVE_Y; |
| case Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Z: return tcu::CUBEFACE_NEGATIVE_Z; |
| case Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_Z: return tcu::CUBEFACE_POSITIVE_Z; |
| default: return tcu::CUBEFACE_LAST; |
| } |
| } |
| |
| static Framebuffer::TexTarget texLayeredTypeToTarget (Texture::Type type) |
| { |
| switch (type) |
| { |
| case Texture::TYPE_2D_ARRAY: return Framebuffer::TEXTARGET_2D_ARRAY; |
| case Texture::TYPE_3D: return Framebuffer::TEXTARGET_3D; |
| case Texture::TYPE_CUBE_MAP_ARRAY: return Framebuffer::TEXTARGET_CUBE_MAP_ARRAY; |
| default: return Framebuffer::TEXTARGET_LAST; |
| } |
| } |
| |
| static tcu::CubeFace mapGLCubeFace (deUint32 face) |
| { |
| switch (face) |
| { |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: return tcu::CUBEFACE_NEGATIVE_X; |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_X: return tcu::CUBEFACE_POSITIVE_X; |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: return tcu::CUBEFACE_NEGATIVE_Y; |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: return tcu::CUBEFACE_POSITIVE_Y; |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: return tcu::CUBEFACE_NEGATIVE_Z; |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: return tcu::CUBEFACE_POSITIVE_Z; |
| default: return tcu::CUBEFACE_LAST; |
| } |
| } |
| |
| tcu::TextureFormat toTextureFormat (const tcu::PixelFormat& pixelFmt) |
| { |
| static const struct |
| { |
| tcu::PixelFormat pixelFmt; |
| tcu::TextureFormat texFmt; |
| } pixelFormatMap[] = |
| { |
| { tcu::PixelFormat(8,8,8,8), tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8) }, |
| { tcu::PixelFormat(8,8,8,0), tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_INT8) }, |
| { tcu::PixelFormat(4,4,4,4), tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_SHORT_4444) }, |
| { tcu::PixelFormat(5,5,5,1), tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_SHORT_5551) }, |
| { tcu::PixelFormat(5,6,5,0), tcu::TextureFormat(tcu::TextureFormat::RGB, tcu::TextureFormat::UNORM_SHORT_565) } |
| }; |
| |
| for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(pixelFormatMap); ndx++) |
| { |
| if (pixelFormatMap[ndx].pixelFmt == pixelFmt) |
| return pixelFormatMap[ndx].texFmt; |
| } |
| |
| TCU_FAIL("Can't map pixel format to texture format"); |
| } |
| |
| tcu::TextureFormat toNonSRGBFormat (const tcu::TextureFormat& fmt) |
| { |
| switch (fmt.order) |
| { |
| case tcu::TextureFormat::sRGB: |
| return tcu::TextureFormat(tcu::TextureFormat::RGB, fmt.type); |
| case tcu::TextureFormat::sRGBA: |
| return tcu::TextureFormat(tcu::TextureFormat::RGBA, fmt.type); |
| default: |
| return fmt; |
| } |
| } |
| |
| tcu::TextureFormat getDepthFormat (int depthBits) |
| { |
| switch (depthBits) |
| { |
| case 8: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT8); |
| case 16: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNORM_INT16); |
| case 24: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::UNSIGNED_INT_24_8); |
| case 32: return tcu::TextureFormat(tcu::TextureFormat::D, tcu::TextureFormat::FLOAT); |
| default: |
| TCU_FAIL("Can't map depth buffer format"); |
| } |
| } |
| |
| tcu::TextureFormat getStencilFormat (int stencilBits) |
| { |
| switch (stencilBits) |
| { |
| case 8: return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT8); |
| case 16: return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT16); |
| case 24: return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT_24_8); |
| case 32: return tcu::TextureFormat(tcu::TextureFormat::S, tcu::TextureFormat::UNSIGNED_INT32); |
| default: |
| TCU_FAIL("Can't map depth buffer format"); |
| } |
| } |
| |
| static inline tcu::IVec4 intersect (const tcu::IVec4& a, const tcu::IVec4& b) |
| { |
| int x0 = de::max(a.x(), b.x()); |
| int y0 = de::max(a.y(), b.y()); |
| int x1 = de::min(a.x()+a.z(), b.x()+b.z()); |
| int y1 = de::min(a.y()+a.w(), b.y()+b.w()); |
| int w = de::max(0, x1-x0); |
| int h = de::max(0, y1-y0); |
| |
| return tcu::IVec4(x0, y0, w, h); |
| } |
| |
| static inline tcu::IVec4 getBufferRect (const rr::MultisampleConstPixelBufferAccess& access) |
| { |
| return tcu::IVec4(0, 0, access.raw().getHeight(), access.raw().getDepth()); |
| } |
| |
| ReferenceContextLimits::ReferenceContextLimits (const glu::RenderContext& renderCtx) |
| : contextType (renderCtx.getType()) |
| , maxTextureImageUnits (0) |
| , maxTexture2DSize (0) |
| , maxTextureCubeSize (0) |
| , maxTexture2DArrayLayers (0) |
| , maxTexture3DSize (0) |
| , maxRenderbufferSize (0) |
| , maxVertexAttribs (0) |
| , subpixelBits (0) |
| { |
| const glw::Functions& gl = renderCtx.getFunctions(); |
| |
| gl.getIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureImageUnits); |
| gl.getIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexture2DSize); |
| gl.getIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &maxTextureCubeSize); |
| gl.getIntegerv(GL_MAX_RENDERBUFFER_SIZE, &maxRenderbufferSize); |
| gl.getIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs); |
| gl.getIntegerv(GL_SUBPIXEL_BITS, &subpixelBits); |
| |
| if (contextSupports(contextType, glu::ApiType::es(3,0)) || glu::isContextTypeGLCore(contextType)) |
| { |
| gl.getIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTexture2DArrayLayers); |
| gl.getIntegerv(GL_MAX_3D_TEXTURE_SIZE, &maxTexture3DSize); |
| } |
| |
| // Limit texture sizes to supported values |
| maxTexture2DSize = de::min(maxTexture2DSize, (int)MAX_TEXTURE_SIZE); |
| maxTextureCubeSize = de::min(maxTextureCubeSize, (int)MAX_TEXTURE_SIZE); |
| maxTexture3DSize = de::min(maxTexture3DSize, (int)MAX_TEXTURE_SIZE); |
| |
| GLU_EXPECT_NO_ERROR(gl.getError(), GL_NO_ERROR); |
| |
| // \todo [pyry] Figure out following things: |
| // + supported fbo configurations |
| // ... |
| |
| // \todo [2013-08-01 pyry] Do we want to make these conditional based on renderCtx? |
| addExtension("GL_EXT_color_buffer_half_float"); |
| addExtension("GL_EXT_color_buffer_float"); |
| |
| if (contextSupports(contextType, glu::ApiType::es(3,1))) |
| addExtension("GL_EXT_texture_cube_map_array"); |
| } |
| |
| void ReferenceContextLimits::addExtension (const char* extension) |
| { |
| extensionList.push_back(extension); |
| |
| if (!extensionStr.empty()) |
| extensionStr += " "; |
| extensionStr += extension; |
| } |
| |
| ReferenceContextBuffers::ReferenceContextBuffers (const tcu::PixelFormat& colorBits, int depthBits, int stencilBits, int width, int height, int samples) |
| { |
| m_colorbuffer.setStorage(toTextureFormat(colorBits), samples, width, height); |
| |
| if (depthBits > 0) |
| m_depthbuffer.setStorage(getDepthFormat(depthBits), samples, width, height); |
| |
| if (stencilBits > 0) |
| m_stencilbuffer.setStorage(getStencilFormat(stencilBits), samples, width, height); |
| } |
| |
| ReferenceContext::StencilState::StencilState (void) |
| : func (GL_ALWAYS) |
| , ref (0) |
| , opMask (~0u) |
| , opStencilFail (GL_KEEP) |
| , opDepthFail (GL_KEEP) |
| , opDepthPass (GL_KEEP) |
| , writeMask (~0u) |
| { |
| } |
| |
| ReferenceContext::ReferenceContext (const ReferenceContextLimits& limits, const rr::MultisamplePixelBufferAccess& colorbuffer, const rr::MultisamplePixelBufferAccess& depthbuffer, const rr::MultisamplePixelBufferAccess& stencilbuffer) |
| : Context (limits.contextType) |
| , m_limits (limits) |
| , m_defaultColorbuffer (colorbuffer) |
| , m_defaultDepthbuffer (depthbuffer) |
| , m_defaultStencilbuffer (stencilbuffer) |
| , m_clientVertexArray (0, m_limits.maxVertexAttribs) |
| |
| , m_viewport (0, 0, colorbuffer.raw().getHeight(), colorbuffer.raw().getDepth()) |
| |
| , m_activeTexture (0) |
| , m_textureUnits (m_limits.maxTextureImageUnits) |
| , m_emptyTex1D () |
| , m_emptyTex2D () |
| , m_emptyTexCube () |
| , m_emptyTex2DArray () |
| , m_emptyTex3D () |
| , m_emptyTexCubeArray () |
| |
| , m_pixelUnpackRowLength (0) |
| , m_pixelUnpackSkipRows (0) |
| , m_pixelUnpackSkipPixels (0) |
| , m_pixelUnpackImageHeight (0) |
| , m_pixelUnpackSkipImages (0) |
| , m_pixelUnpackAlignment (4) |
| , m_pixelPackAlignment (4) |
| |
| , m_readFramebufferBinding (DE_NULL) |
| , m_drawFramebufferBinding (DE_NULL) |
| , m_renderbufferBinding (DE_NULL) |
| , m_vertexArrayBinding (DE_NULL) |
| , m_currentProgram (DE_NULL) |
| |
| , m_arrayBufferBinding (DE_NULL) |
| , m_pixelPackBufferBinding (DE_NULL) |
| , m_pixelUnpackBufferBinding (DE_NULL) |
| , m_transformFeedbackBufferBinding (DE_NULL) |
| , m_uniformBufferBinding (DE_NULL) |
| , m_copyReadBufferBinding (DE_NULL) |
| , m_copyWriteBufferBinding (DE_NULL) |
| , m_drawIndirectBufferBinding (DE_NULL) |
| |
| , m_clearColor (0.0f, 0.0f, 0.0f, 0.0f) |
| , m_clearDepth (1.0f) |
| , m_clearStencil (0) |
| , m_scissorEnabled (false) |
| , m_scissorBox (m_viewport) |
| , m_stencilTestEnabled (false) |
| , m_depthTestEnabled (false) |
| , m_depthFunc (GL_LESS) |
| , m_depthRangeNear (0.0f) |
| , m_depthRangeFar (1.0f) |
| , m_polygonOffsetFactor (0.0f) |
| , m_polygonOffsetUnits (0.0f) |
| , m_polygonOffsetFillEnabled (false) |
| , m_provokingFirstVertexConvention (false) |
| , m_blendEnabled (false) |
| , m_blendModeRGB (GL_FUNC_ADD) |
| , m_blendModeAlpha (GL_FUNC_ADD) |
| , m_blendFactorSrcRGB (GL_ONE) |
| , m_blendFactorDstRGB (GL_ZERO) |
| , m_blendFactorSrcAlpha (GL_ONE) |
| , m_blendFactorDstAlpha (GL_ZERO) |
| , m_blendColor (0.0f, 0.0f, 0.0f, 0.0f) |
| , m_sRGBUpdateEnabled (true) |
| , m_depthClampEnabled (false) |
| , m_colorMask (true, true, true, true) |
| , m_depthMask (true) |
| , m_currentAttribs (m_limits.maxVertexAttribs, rr::GenericVec4(tcu::Vec4(0, 0, 0, 1))) |
| , m_lineWidth (1.0f) |
| , m_primitiveRestartFixedIndex (false) |
| , m_primitiveRestartSettableIndex (false) |
| , m_primitiveRestartIndex (0) |
| |
| , m_lastError (GL_NO_ERROR) |
| { |
| // Create empty textures to be used when texture objects are incomplete. |
| m_emptyTex1D.getSampler().wrapS = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTex1D.getSampler().wrapT = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTex1D.getSampler().minFilter = tcu::Sampler::NEAREST; |
| m_emptyTex1D.getSampler().magFilter = tcu::Sampler::NEAREST; |
| m_emptyTex1D.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1); |
| m_emptyTex1D.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0); |
| m_emptyTex1D.updateView(tcu::Sampler::MODE_LAST); |
| |
| m_emptyTex2D.getSampler().wrapS = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTex2D.getSampler().wrapT = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTex2D.getSampler().minFilter = tcu::Sampler::NEAREST; |
| m_emptyTex2D.getSampler().magFilter = tcu::Sampler::NEAREST; |
| m_emptyTex2D.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1); |
| m_emptyTex2D.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0); |
| m_emptyTex2D.updateView(tcu::Sampler::MODE_LAST); |
| |
| m_emptyTexCube.getSampler().wrapS = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTexCube.getSampler().wrapT = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTexCube.getSampler().minFilter = tcu::Sampler::NEAREST; |
| m_emptyTexCube.getSampler().magFilter = tcu::Sampler::NEAREST; |
| for (int face = 0; face < tcu::CUBEFACE_LAST; face++) |
| { |
| m_emptyTexCube.allocFace(0, (tcu::CubeFace)face, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1); |
| m_emptyTexCube.getFace(0, (tcu::CubeFace)face).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0); |
| } |
| m_emptyTexCube.updateView(tcu::Sampler::MODE_LAST); |
| |
| m_emptyTex2DArray.getSampler().wrapS = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTex2DArray.getSampler().wrapT = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTex2DArray.getSampler().minFilter = tcu::Sampler::NEAREST; |
| m_emptyTex2DArray.getSampler().magFilter = tcu::Sampler::NEAREST; |
| m_emptyTex2DArray.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1, 1); |
| m_emptyTex2DArray.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0); |
| m_emptyTex2DArray.updateView(tcu::Sampler::MODE_LAST); |
| |
| m_emptyTex3D.getSampler().wrapS = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTex3D.getSampler().wrapT = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTex3D.getSampler().wrapR = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTex3D.getSampler().minFilter = tcu::Sampler::NEAREST; |
| m_emptyTex3D.getSampler().magFilter = tcu::Sampler::NEAREST; |
| m_emptyTex3D.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1, 1); |
| m_emptyTex3D.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0); |
| m_emptyTex3D.updateView(tcu::Sampler::MODE_LAST); |
| |
| m_emptyTexCubeArray.getSampler().wrapS = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTexCubeArray.getSampler().wrapT = tcu::Sampler::CLAMP_TO_EDGE; |
| m_emptyTexCubeArray.getSampler().minFilter = tcu::Sampler::NEAREST; |
| m_emptyTexCubeArray.getSampler().magFilter = tcu::Sampler::NEAREST; |
| m_emptyTexCubeArray.allocLevel(0, tcu::TextureFormat(tcu::TextureFormat::RGBA, tcu::TextureFormat::UNORM_INT8), 1, 1, 6); |
| for (int faceNdx = 0; faceNdx < 6; faceNdx++) |
| m_emptyTexCubeArray.getLevel(0).setPixel(Vec4(0.0f, 0.0f, 0.0f, 1.0f), 0, 0, faceNdx); |
| m_emptyTexCubeArray.updateView(tcu::Sampler::MODE_LAST); |
| |
| if (glu::isContextTypeGLCore(getType())) |
| m_sRGBUpdateEnabled = false; |
| } |
| |
| ReferenceContext::~ReferenceContext (void) |
| { |
| // Destroy all objects -- verifies that ref counting works |
| { |
| vector<VertexArray*> vertexArrays; |
| m_vertexArrays.getAll(vertexArrays); |
| for (vector<VertexArray*>::iterator i = vertexArrays.begin(); i != vertexArrays.end(); i++) |
| deleteVertexArray(*i); |
| |
| DE_ASSERT(m_clientVertexArray.getRefCount() == 1); |
| } |
| |
| { |
| vector<Texture*> textures; |
| m_textures.getAll(textures); |
| for (vector<Texture*>::iterator i = textures.begin(); i != textures.end(); i++) |
| deleteTexture(*i); |
| } |
| |
| { |
| vector<Framebuffer*> framebuffers; |
| m_framebuffers.getAll(framebuffers); |
| for (vector<Framebuffer*>::iterator i = framebuffers.begin(); i != framebuffers.end(); i++) |
| deleteFramebuffer(*i); |
| } |
| |
| { |
| vector<Renderbuffer*> renderbuffers; |
| m_renderbuffers.getAll(renderbuffers); |
| for (vector<Renderbuffer*>::iterator i = renderbuffers.begin(); i != renderbuffers.end(); i++) |
| deleteRenderbuffer(*i); |
| } |
| |
| { |
| vector<DataBuffer*> buffers; |
| m_buffers.getAll(buffers); |
| for (vector<DataBuffer*>::iterator i = buffers.begin(); i != buffers.end(); i++) |
| deleteBuffer(*i); |
| } |
| |
| { |
| vector<ShaderProgramObjectContainer*> programs; |
| m_programs.getAll(programs); |
| for (vector<ShaderProgramObjectContainer*>::iterator i = programs.begin(); i != programs.end(); i++) |
| deleteProgramObject(*i); |
| } |
| } |
| |
| void ReferenceContext::activeTexture (deUint32 texture) |
| { |
| if (deInBounds32(texture, GL_TEXTURE0, GL_TEXTURE0 + (deUint32)m_textureUnits.size())) |
| m_activeTexture = texture - GL_TEXTURE0; |
| else |
| setError(GL_INVALID_ENUM); |
| } |
| |
| void ReferenceContext::setTex1DBinding (int unitNdx, Texture1D* texture) |
| { |
| if (m_textureUnits[unitNdx].tex1DBinding) |
| { |
| m_textures.releaseReference(m_textureUnits[unitNdx].tex1DBinding); |
| m_textureUnits[unitNdx].tex1DBinding = DE_NULL; |
| } |
| |
| if (texture) |
| { |
| m_textures.acquireReference(texture); |
| m_textureUnits[unitNdx].tex1DBinding = texture; |
| } |
| } |
| |
| void ReferenceContext::setTex2DBinding (int unitNdx, Texture2D* texture) |
| { |
| if (m_textureUnits[unitNdx].tex2DBinding) |
| { |
| m_textures.releaseReference(m_textureUnits[unitNdx].tex2DBinding); |
| m_textureUnits[unitNdx].tex2DBinding = DE_NULL; |
| } |
| |
| if (texture) |
| { |
| m_textures.acquireReference(texture); |
| m_textureUnits[unitNdx].tex2DBinding = texture; |
| } |
| } |
| |
| void ReferenceContext::setTexCubeBinding (int unitNdx, TextureCube* texture) |
| { |
| if (m_textureUnits[unitNdx].texCubeBinding) |
| { |
| m_textures.releaseReference(m_textureUnits[unitNdx].texCubeBinding); |
| m_textureUnits[unitNdx].texCubeBinding = DE_NULL; |
| } |
| |
| if (texture) |
| { |
| m_textures.acquireReference(texture); |
| m_textureUnits[unitNdx].texCubeBinding = texture; |
| } |
| } |
| |
| void ReferenceContext::setTex2DArrayBinding (int unitNdx, Texture2DArray* texture) |
| { |
| if (m_textureUnits[unitNdx].tex2DArrayBinding) |
| { |
| m_textures.releaseReference(m_textureUnits[unitNdx].tex2DArrayBinding); |
| m_textureUnits[unitNdx].tex2DArrayBinding = DE_NULL; |
| } |
| |
| if (texture) |
| { |
| m_textures.acquireReference(texture); |
| m_textureUnits[unitNdx].tex2DArrayBinding = texture; |
| } |
| } |
| |
| void ReferenceContext::setTex3DBinding (int unitNdx, Texture3D* texture) |
| { |
| if (m_textureUnits[unitNdx].tex3DBinding) |
| { |
| m_textures.releaseReference(m_textureUnits[unitNdx].tex3DBinding); |
| m_textureUnits[unitNdx].tex3DBinding = DE_NULL; |
| } |
| |
| if (texture) |
| { |
| m_textures.acquireReference(texture); |
| m_textureUnits[unitNdx].tex3DBinding = texture; |
| } |
| } |
| |
| void ReferenceContext::setTexCubeArrayBinding (int unitNdx, TextureCubeArray* texture) |
| { |
| if (m_textureUnits[unitNdx].texCubeArrayBinding) |
| { |
| m_textures.releaseReference(m_textureUnits[unitNdx].texCubeArrayBinding); |
| m_textureUnits[unitNdx].texCubeArrayBinding = DE_NULL; |
| } |
| |
| if (texture) |
| { |
| m_textures.acquireReference(texture); |
| m_textureUnits[unitNdx].texCubeArrayBinding = texture; |
| } |
| } |
| |
| void ReferenceContext::bindTexture (deUint32 target, deUint32 texture) |
| { |
| int unitNdx = m_activeTexture; |
| |
| RC_IF_ERROR(target != GL_TEXTURE_1D && |
| target != GL_TEXTURE_2D && |
| target != GL_TEXTURE_CUBE_MAP && |
| target != GL_TEXTURE_2D_ARRAY && |
| target != GL_TEXTURE_3D && |
| target != GL_TEXTURE_CUBE_MAP_ARRAY, |
| GL_INVALID_ENUM, RC_RET_VOID); |
| |
| RC_IF_ERROR(glu::isContextTypeES(m_limits.contextType) && (target == GL_TEXTURE_1D), GL_INVALID_ENUM, RC_RET_VOID); |
| |
| if (texture == 0) |
| { |
| // Clear binding. |
| switch (target) |
| { |
| case GL_TEXTURE_1D: setTex1DBinding (unitNdx, DE_NULL); break; |
| case GL_TEXTURE_2D: setTex2DBinding (unitNdx, DE_NULL); break; |
| case GL_TEXTURE_CUBE_MAP: setTexCubeBinding (unitNdx, DE_NULL); break; |
| case GL_TEXTURE_2D_ARRAY: setTex2DArrayBinding (unitNdx, DE_NULL); break; |
| case GL_TEXTURE_3D: setTex3DBinding (unitNdx, DE_NULL); break; |
| case GL_TEXTURE_CUBE_MAP_ARRAY: setTexCubeArrayBinding (unitNdx, DE_NULL); break; |
| default: |
| DE_ASSERT(false); |
| } |
| } |
| else |
| { |
| Texture* texObj = m_textures.find(texture); |
| |
| if (texObj) |
| { |
| // Validate type. |
| Texture::Type expectedType = Texture::TYPE_LAST; |
| switch (target) |
| { |
| case GL_TEXTURE_1D: expectedType = Texture::TYPE_1D; break; |
| case GL_TEXTURE_2D: expectedType = Texture::TYPE_2D; break; |
| case GL_TEXTURE_CUBE_MAP: expectedType = Texture::TYPE_CUBE_MAP; break; |
| case GL_TEXTURE_2D_ARRAY: expectedType = Texture::TYPE_2D_ARRAY; break; |
| case GL_TEXTURE_3D: expectedType = Texture::TYPE_3D; break; |
| case GL_TEXTURE_CUBE_MAP_ARRAY: expectedType = Texture::TYPE_CUBE_MAP_ARRAY; break; |
| default: |
| DE_ASSERT(false); |
| } |
| RC_IF_ERROR(texObj->getType() != expectedType, GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| else |
| { |
| // New texture object. |
| switch (target) |
| { |
| case GL_TEXTURE_1D: texObj = new Texture1D (texture); break; |
| case GL_TEXTURE_2D: texObj = new Texture2D (texture); break; |
| case GL_TEXTURE_CUBE_MAP: texObj = new TextureCube (texture); break; |
| case GL_TEXTURE_2D_ARRAY: texObj = new Texture2DArray (texture); break; |
| case GL_TEXTURE_3D: texObj = new Texture3D (texture); break; |
| case GL_TEXTURE_CUBE_MAP_ARRAY: texObj = new TextureCubeArray (texture); break; |
| default: |
| DE_ASSERT(false); |
| } |
| |
| m_textures.insert(texObj); |
| } |
| |
| switch (target) |
| { |
| case GL_TEXTURE_1D: setTex1DBinding (unitNdx, static_cast<Texture1D*> (texObj)); break; |
| case GL_TEXTURE_2D: setTex2DBinding (unitNdx, static_cast<Texture2D*> (texObj)); break; |
| case GL_TEXTURE_CUBE_MAP: setTexCubeBinding (unitNdx, static_cast<TextureCube*> (texObj)); break; |
| case GL_TEXTURE_2D_ARRAY: setTex2DArrayBinding (unitNdx, static_cast<Texture2DArray*> (texObj)); break; |
| case GL_TEXTURE_3D: setTex3DBinding (unitNdx, static_cast<Texture3D*> (texObj)); break; |
| case GL_TEXTURE_CUBE_MAP_ARRAY: setTexCubeArrayBinding (unitNdx, static_cast<TextureCubeArray*> (texObj)); break; |
| default: |
| DE_ASSERT(false); |
| } |
| } |
| } |
| |
| void ReferenceContext::genTextures (int numTextures, deUint32* textures) |
| { |
| while (numTextures--) |
| *textures++ = m_textures.allocateName(); |
| } |
| |
| void ReferenceContext::deleteTextures (int numTextures, const deUint32* textures) |
| { |
| for (int i = 0; i < numTextures; i++) |
| { |
| deUint32 name = textures[i]; |
| Texture* texture = name ? m_textures.find(name) : DE_NULL; |
| |
| if (texture) |
| deleteTexture(texture); |
| } |
| } |
| |
| void ReferenceContext::deleteTexture (Texture* texture) |
| { |
| // Unbind from context |
| for (int unitNdx = 0; unitNdx < (int)m_textureUnits.size(); unitNdx++) |
| { |
| if (m_textureUnits[unitNdx].tex1DBinding == texture) setTex1DBinding (unitNdx, DE_NULL); |
| else if (m_textureUnits[unitNdx].tex2DBinding == texture) setTex2DBinding (unitNdx, DE_NULL); |
| else if (m_textureUnits[unitNdx].texCubeBinding == texture) setTexCubeBinding (unitNdx, DE_NULL); |
| else if (m_textureUnits[unitNdx].tex2DArrayBinding == texture) setTex2DArrayBinding (unitNdx, DE_NULL); |
| else if (m_textureUnits[unitNdx].tex3DBinding == texture) setTex3DBinding (unitNdx, DE_NULL); |
| else if (m_textureUnits[unitNdx].texCubeArrayBinding == texture) setTexCubeArrayBinding (unitNdx, DE_NULL); |
| } |
| |
| // Unbind from currently bound framebuffers |
| for (int ndx = 0; ndx < 2; ndx++) |
| { |
| rc::Framebuffer* framebufferBinding = ndx ? m_drawFramebufferBinding : m_readFramebufferBinding; |
| if (framebufferBinding) |
| { |
| int releaseRefCount = (framebufferBinding == m_drawFramebufferBinding ? 1 : 0) |
| + (framebufferBinding == m_readFramebufferBinding ? 1 : 0); |
| |
| for (int point = 0; point < Framebuffer::ATTACHMENTPOINT_LAST; point++) |
| { |
| Framebuffer::Attachment& attachment = framebufferBinding->getAttachment((Framebuffer::AttachmentPoint)point); |
| if (attachment.name == texture->getName()) |
| { |
| for (int refNdx = 0; refNdx < releaseRefCount; refNdx++) |
| releaseFboAttachmentReference(attachment); |
| attachment = Framebuffer::Attachment(); |
| } |
| } |
| } |
| } |
| |
| DE_ASSERT(texture->getRefCount() == 1); |
| m_textures.releaseReference(texture); |
| } |
| |
| void ReferenceContext::bindFramebuffer (deUint32 target, deUint32 name) |
| { |
| Framebuffer* fbo = DE_NULL; |
| |
| RC_IF_ERROR(target != GL_FRAMEBUFFER && |
| target != GL_DRAW_FRAMEBUFFER && |
| target != GL_READ_FRAMEBUFFER, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| if (name != 0) |
| { |
| // Find or create framebuffer object. |
| fbo = m_framebuffers.find(name); |
| if (!fbo) |
| { |
| fbo = new Framebuffer(name); |
| m_framebuffers.insert(fbo); |
| } |
| } |
| |
| for (int ndx = 0; ndx < 2; ndx++) |
| { |
| deUint32 bindingTarget = ndx ? GL_DRAW_FRAMEBUFFER : GL_READ_FRAMEBUFFER; |
| rc::Framebuffer*& binding = ndx ? m_drawFramebufferBinding : m_readFramebufferBinding; |
| |
| if (target != GL_FRAMEBUFFER && target != bindingTarget) |
| continue; // Doesn't match this target. |
| |
| // Remove old references |
| if (binding) |
| { |
| // Clear all attachment point references |
| for (int point = 0; point < Framebuffer::ATTACHMENTPOINT_LAST; point++) |
| releaseFboAttachmentReference(binding->getAttachment((Framebuffer::AttachmentPoint)point)); |
| |
| m_framebuffers.releaseReference(binding); |
| } |
| |
| // Create new references |
| if (fbo) |
| { |
| m_framebuffers.acquireReference(fbo); |
| |
| for (int point = 0; point < Framebuffer::ATTACHMENTPOINT_LAST; point++) |
| acquireFboAttachmentReference(fbo->getAttachment((Framebuffer::AttachmentPoint)point)); |
| } |
| |
| binding = fbo; |
| } |
| } |
| |
| void ReferenceContext::genFramebuffers (int numFramebuffers, deUint32* framebuffers) |
| { |
| while (numFramebuffers--) |
| *framebuffers++ = m_framebuffers.allocateName(); |
| } |
| |
| void ReferenceContext::deleteFramebuffer (Framebuffer* framebuffer) |
| { |
| // Remove bindings. |
| if (m_drawFramebufferBinding == framebuffer) bindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); |
| if (m_readFramebufferBinding == framebuffer) bindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| |
| DE_ASSERT(framebuffer->getRefCount() == 1); |
| m_framebuffers.releaseReference(framebuffer); |
| } |
| |
| void ReferenceContext::deleteFramebuffers (int numFramebuffers, const deUint32* framebuffers) |
| { |
| for (int i = 0; i < numFramebuffers; i++) |
| { |
| deUint32 name = framebuffers[i]; |
| Framebuffer* framebuffer = name ? m_framebuffers.find(name) : DE_NULL; |
| |
| if (framebuffer) |
| deleteFramebuffer(framebuffer); |
| } |
| } |
| |
| void ReferenceContext::bindRenderbuffer (deUint32 target, deUint32 name) |
| { |
| Renderbuffer* rbo = DE_NULL; |
| |
| RC_IF_ERROR(target != GL_RENDERBUFFER, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| if (name != 0) |
| { |
| rbo = m_renderbuffers.find(name); |
| if (!rbo) |
| { |
| rbo = new Renderbuffer(name); |
| m_renderbuffers.insert(rbo); |
| } |
| } |
| |
| // Remove old reference |
| if (m_renderbufferBinding) |
| m_renderbuffers.releaseReference(m_renderbufferBinding); |
| |
| // Create new reference |
| if (rbo) |
| m_renderbuffers.acquireReference(rbo); |
| |
| m_renderbufferBinding = rbo; |
| } |
| |
| void ReferenceContext::genRenderbuffers (int numRenderbuffers, deUint32* renderbuffers) |
| { |
| while (numRenderbuffers--) |
| *renderbuffers++ = m_renderbuffers.allocateName(); |
| } |
| |
| void ReferenceContext::deleteRenderbuffer (Renderbuffer* renderbuffer) |
| { |
| if (m_renderbufferBinding == renderbuffer) |
| bindRenderbuffer(GL_RENDERBUFFER, 0); |
| |
| // Unbind from currently bound framebuffers |
| for (int ndx = 0; ndx < 2; ndx++) |
| { |
| rc::Framebuffer* framebufferBinding = ndx ? m_drawFramebufferBinding : m_readFramebufferBinding; |
| if (framebufferBinding) |
| { |
| int releaseRefCount = (framebufferBinding == m_drawFramebufferBinding ? 1 : 0) |
| + (framebufferBinding == m_readFramebufferBinding ? 1 : 0); |
| |
| for (int point = 0; point < Framebuffer::ATTACHMENTPOINT_LAST; point++) |
| { |
| Framebuffer::Attachment& attachment = framebufferBinding->getAttachment((Framebuffer::AttachmentPoint)point); |
| if (attachment.name == renderbuffer->getName()) |
| { |
| for (int refNdx = 0; refNdx < releaseRefCount; refNdx++) |
| releaseFboAttachmentReference(attachment); |
| attachment = Framebuffer::Attachment(); |
| } |
| } |
| } |
| } |
| |
| DE_ASSERT(renderbuffer->getRefCount() == 1); |
| m_renderbuffers.releaseReference(renderbuffer); |
| } |
| |
| void ReferenceContext::deleteRenderbuffers (int numRenderbuffers, const deUint32* renderbuffers) |
| { |
| for (int i = 0; i < numRenderbuffers; i++) |
| { |
| deUint32 name = renderbuffers[i]; |
| Renderbuffer* renderbuffer = name ? m_renderbuffers.find(name) : DE_NULL; |
| |
| if (renderbuffer) |
| deleteRenderbuffer(renderbuffer); |
| } |
| } |
| |
| void ReferenceContext::pixelStorei (deUint32 pname, int param) |
| { |
| switch (pname) |
| { |
| case GL_UNPACK_ALIGNMENT: |
| RC_IF_ERROR(param != 1 && param != 2 && param != 4 && param != 8, GL_INVALID_VALUE, RC_RET_VOID); |
| m_pixelUnpackAlignment = param; |
| break; |
| |
| case GL_PACK_ALIGNMENT: |
| RC_IF_ERROR(param != 1 && param != 2 && param != 4 && param != 8, GL_INVALID_VALUE, RC_RET_VOID); |
| m_pixelPackAlignment = param; |
| break; |
| |
| case GL_UNPACK_ROW_LENGTH: |
| RC_IF_ERROR(param < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| m_pixelUnpackRowLength = param; |
| break; |
| |
| case GL_UNPACK_SKIP_ROWS: |
| RC_IF_ERROR(param < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| m_pixelUnpackSkipRows = param; |
| break; |
| |
| case GL_UNPACK_SKIP_PIXELS: |
| RC_IF_ERROR(param < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| m_pixelUnpackSkipPixels = param; |
| break; |
| |
| case GL_UNPACK_IMAGE_HEIGHT: |
| RC_IF_ERROR(param < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| m_pixelUnpackImageHeight = param; |
| break; |
| |
| case GL_UNPACK_SKIP_IMAGES: |
| RC_IF_ERROR(param < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| m_pixelUnpackSkipImages = param; |
| break; |
| |
| default: |
| setError(GL_INVALID_ENUM); |
| } |
| } |
| |
| tcu::ConstPixelBufferAccess ReferenceContext::getUnpack2DAccess (const tcu::TextureFormat& format, int width, int height, const void* data) |
| { |
| int pixelSize = format.getPixelSize(); |
| int rowLen = m_pixelUnpackRowLength > 0 ? m_pixelUnpackRowLength : width; |
| int rowPitch = deAlign32(rowLen*pixelSize, m_pixelUnpackAlignment); |
| const deUint8* ptr = (const deUint8*)data + m_pixelUnpackSkipRows*rowPitch + m_pixelUnpackSkipPixels*pixelSize; |
| |
| return tcu::ConstPixelBufferAccess(format, width, height, 1, rowPitch, 0, ptr); |
| } |
| |
| tcu::ConstPixelBufferAccess ReferenceContext::getUnpack3DAccess (const tcu::TextureFormat& format, int width, int height, int depth, const void* data) |
| { |
| int pixelSize = format.getPixelSize(); |
| int rowLen = m_pixelUnpackRowLength > 0 ? m_pixelUnpackRowLength : width; |
| int imageHeight = m_pixelUnpackImageHeight > 0 ? m_pixelUnpackImageHeight : height; |
| int rowPitch = deAlign32(rowLen*pixelSize, m_pixelUnpackAlignment); |
| int slicePitch = imageHeight*rowPitch; |
| const deUint8* ptr = (const deUint8*)data + m_pixelUnpackSkipImages*slicePitch + m_pixelUnpackSkipRows*rowPitch + m_pixelUnpackSkipPixels*pixelSize; |
| |
| return tcu::ConstPixelBufferAccess(format, width, height, depth, rowPitch, slicePitch, ptr); |
| } |
| |
| static tcu::TextureFormat mapInternalFormat (deUint32 internalFormat) |
| { |
| switch (internalFormat) |
| { |
| case GL_ALPHA: return TextureFormat(TextureFormat::A, TextureFormat::UNORM_INT8); |
| case GL_LUMINANCE: return TextureFormat(TextureFormat::L, TextureFormat::UNORM_INT8); |
| case GL_LUMINANCE_ALPHA: return TextureFormat(TextureFormat::LA, TextureFormat::UNORM_INT8); |
| case GL_RGB: return TextureFormat(TextureFormat::RGB, TextureFormat::UNORM_INT8); |
| case GL_RGBA: return TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8); |
| |
| default: |
| return glu::mapGLInternalFormat(internalFormat); |
| } |
| } |
| |
| static void depthValueFloatClampCopy (const PixelBufferAccess& dst, const ConstPixelBufferAccess& src) |
| { |
| int width = dst.getWidth(); |
| int height = dst.getHeight(); |
| int depth = dst.getDepth(); |
| |
| DE_ASSERT(src.getWidth() == width && src.getHeight() == height && src.getDepth() == depth); |
| |
| // clamping copy |
| |
| if (src.getFormat().order == tcu::TextureFormat::DS && dst.getFormat().order == tcu::TextureFormat::DS) |
| { |
| // copy only depth and stencil |
| for (int z = 0; z < depth; z++) |
| for (int y = 0; y < height; y++) |
| for (int x = 0; x < width; x++) |
| { |
| dst.setPixDepth(de::clamp(src.getPixDepth(x, y, z), 0.0f, 1.0f), x, y, z); |
| dst.setPixStencil(src.getPixStencil(x, y, z), x, y, z); |
| } |
| } |
| else |
| { |
| // copy only depth |
| for (int z = 0; z < depth; z++) |
| for (int y = 0; y < height; y++) |
| for (int x = 0; x < width; x++) |
| dst.setPixDepth(de::clamp(src.getPixDepth(x, y, z), 0.0f, 1.0f), x, y, z); |
| } |
| } |
| |
| void ReferenceContext::texImage1D (deUint32 target, int level, deUint32 internalFormat, int width, int border, deUint32 format, deUint32 type, const void* data) |
| { |
| texImage2D(target, level, internalFormat, width, 1, border, format, type, data); |
| } |
| |
| void ReferenceContext::texImage2D (deUint32 target, int level, deUint32 internalFormat, int width, int height, int border, deUint32 format, deUint32 type, const void* data) |
| { |
| texImage3D(target, level, internalFormat, width, height, 1, border, format, type, data); |
| } |
| |
| static void clearToTextureInitialValue (PixelBufferAccess access) |
| { |
| const bool hasDepth = access.getFormat().order == tcu::TextureFormat::D || access.getFormat().order == tcu::TextureFormat::DS; |
| const bool hasStencil = access.getFormat().order == tcu::TextureFormat::S || access.getFormat().order == tcu::TextureFormat::DS; |
| const bool hasColor = !hasDepth && !hasStencil; |
| |
| if (hasDepth) |
| tcu::clearDepth(access, 0.0f); |
| if (hasStencil) |
| tcu::clearStencil(access, 0u); |
| if (hasColor) |
| tcu::clear(access, Vec4(0.0f, 0.0f, 0.0f, 1.0f)); |
| } |
| |
| void ReferenceContext::texImage3D (deUint32 target, int level, deUint32 internalFormat, int width, int height, int depth, int border, deUint32 format, deUint32 type, const void* data) |
| { |
| TextureUnit& unit = m_textureUnits[m_activeTexture]; |
| const void* unpackPtr = getPixelUnpackPtr(data); |
| const bool isDstFloatDepthFormat = (internalFormat == GL_DEPTH_COMPONENT32F || internalFormat == GL_DEPTH32F_STENCIL8); // depth components are limited to [0,1] range |
| TextureFormat storageFmt; |
| TextureFormat transferFmt; |
| |
| RC_IF_ERROR(border != 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(width < 0 || height < 0 || depth < 0 || level < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| |
| // Map storage format. |
| storageFmt = mapInternalFormat(internalFormat); |
| RC_IF_ERROR(storageFmt.order == TextureFormat::CHANNELORDER_LAST || |
| storageFmt.type == TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| // Map transfer format. |
| transferFmt = glu::mapGLTransferFormat(format, type); |
| RC_IF_ERROR(transferFmt.order == TextureFormat::CHANNELORDER_LAST || |
| transferFmt.type == TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| if (target == GL_TEXTURE_1D && glu::isContextTypeGLCore(m_limits.contextType)) |
| { |
| // Validate size and level. |
| RC_IF_ERROR(width > m_limits.maxTexture2DSize || height != 1 || depth != 1, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| Texture1D* texture = unit.tex1DBinding ? unit.tex1DBinding : &unit.default1DTex; |
| |
| if (texture->isImmutable()) |
| { |
| RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| ConstPixelBufferAccess dst(texture->getLevel(level)); |
| RC_IF_ERROR(storageFmt != dst.getFormat() || |
| width != dst.getWidth(), GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| else |
| texture->allocLevel(level, storageFmt, width); |
| |
| if (unpackPtr) |
| { |
| ConstPixelBufferAccess src = getUnpack2DAccess(transferFmt, width, 1, unpackPtr); |
| PixelBufferAccess dst (texture->getLevel(level)); |
| |
| if (isDstFloatDepthFormat) |
| depthValueFloatClampCopy(dst, src); |
| else |
| tcu::copy(dst, src); |
| } |
| else |
| { |
| // No data supplied, clear to initial |
| clearToTextureInitialValue(texture->getLevel(level)); |
| } |
| } |
| else if (target == GL_TEXTURE_2D) |
| { |
| // Validate size and level. |
| RC_IF_ERROR(width > m_limits.maxTexture2DSize || height > m_limits.maxTexture2DSize || depth != 1, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| Texture2D* texture = unit.tex2DBinding ? unit.tex2DBinding : &unit.default2DTex; |
| |
| if (texture->isImmutable()) |
| { |
| RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| ConstPixelBufferAccess dst(texture->getLevel(level)); |
| RC_IF_ERROR(storageFmt != dst.getFormat() || |
| width != dst.getWidth() || |
| height != dst.getHeight(), GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| else |
| texture->allocLevel(level, storageFmt, width, height); |
| |
| if (unpackPtr) |
| { |
| ConstPixelBufferAccess src = getUnpack2DAccess(transferFmt, width, height, unpackPtr); |
| PixelBufferAccess dst (texture->getLevel(level)); |
| |
| if (isDstFloatDepthFormat) |
| depthValueFloatClampCopy(dst, src); |
| else |
| tcu::copy(dst, src); |
| } |
| else |
| { |
| // No data supplied, clear to initial |
| clearToTextureInitialValue(texture->getLevel(level)); |
| } |
| } |
| else if (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_X || |
| target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y || |
| target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z) |
| { |
| // Validate size and level. |
| RC_IF_ERROR(width != height || width > m_limits.maxTextureCubeSize || depth != 1, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTextureCubeSize), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| TextureCube* texture = unit.texCubeBinding ? unit.texCubeBinding : &unit.defaultCubeTex; |
| tcu::CubeFace face = mapGLCubeFace(target); |
| |
| if (texture->isImmutable()) |
| { |
| RC_IF_ERROR(!texture->hasFace(level, face), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| ConstPixelBufferAccess dst(texture->getFace(level, face)); |
| RC_IF_ERROR(storageFmt != dst.getFormat() || |
| width != dst.getWidth() || |
| height != dst.getHeight(), GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| else |
| texture->allocFace(level, face, storageFmt, width, height); |
| |
| if (unpackPtr) |
| { |
| ConstPixelBufferAccess src = getUnpack2DAccess(transferFmt, width, height, unpackPtr); |
| PixelBufferAccess dst (texture->getFace(level, face)); |
| |
| if (isDstFloatDepthFormat) |
| depthValueFloatClampCopy(dst, src); |
| else |
| tcu::copy(dst, src); |
| } |
| else |
| { |
| // No data supplied, clear to initial |
| clearToTextureInitialValue(texture->getFace(level, face)); |
| } |
| } |
| else if (target == GL_TEXTURE_2D_ARRAY) |
| { |
| // Validate size and level. |
| RC_IF_ERROR(width > m_limits.maxTexture2DSize || |
| height > m_limits.maxTexture2DSize || |
| depth > m_limits.maxTexture2DArrayLayers, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| Texture2DArray* texture = unit.tex2DArrayBinding ? unit.tex2DArrayBinding : &unit.default2DArrayTex; |
| |
| if (texture->isImmutable()) |
| { |
| RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| ConstPixelBufferAccess dst(texture->getLevel(level)); |
| RC_IF_ERROR(storageFmt != dst.getFormat() || |
| width != dst.getWidth() || |
| height != dst.getHeight() || |
| depth != dst.getDepth(), GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| else |
| texture->allocLevel(level, storageFmt, width, height, depth); |
| |
| if (unpackPtr) |
| { |
| ConstPixelBufferAccess src = getUnpack3DAccess(transferFmt, width, height, depth, unpackPtr); |
| PixelBufferAccess dst (texture->getLevel(level)); |
| |
| if (isDstFloatDepthFormat) |
| depthValueFloatClampCopy(dst, src); |
| else |
| tcu::copy(dst, src); |
| } |
| else |
| { |
| // No data supplied, clear to initial |
| clearToTextureInitialValue(texture->getLevel(level)); |
| } |
| } |
| else if (target == GL_TEXTURE_3D) |
| { |
| // Validate size and level. |
| RC_IF_ERROR(width > m_limits.maxTexture3DSize || |
| height > m_limits.maxTexture3DSize || |
| depth > m_limits.maxTexture3DSize, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture3DSize), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| Texture3D* texture = unit.tex3DBinding ? unit.tex3DBinding : &unit.default3DTex; |
| |
| if (texture->isImmutable()) |
| { |
| RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| ConstPixelBufferAccess dst(texture->getLevel(level)); |
| RC_IF_ERROR(storageFmt != dst.getFormat() || |
| width != dst.getWidth() || |
| height != dst.getHeight() || |
| depth != dst.getDepth(), GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| else |
| texture->allocLevel(level, storageFmt, width, height, depth); |
| |
| if (unpackPtr) |
| { |
| ConstPixelBufferAccess src = getUnpack3DAccess(transferFmt, width, height, depth, unpackPtr); |
| PixelBufferAccess dst (texture->getLevel(level)); |
| |
| if (isDstFloatDepthFormat) |
| depthValueFloatClampCopy(dst, src); |
| else |
| tcu::copy(dst, src); |
| } |
| else |
| { |
| // No data supplied, clear to initial |
| clearToTextureInitialValue(texture->getLevel(level)); |
| } |
| } |
| else if (target == GL_TEXTURE_CUBE_MAP_ARRAY) |
| { |
| // Validate size and level. |
| RC_IF_ERROR(width != height || |
| width > m_limits.maxTexture2DSize || |
| depth % 6 != 0 || |
| depth > m_limits.maxTexture2DArrayLayers, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| TextureCubeArray* texture = unit.texCubeArrayBinding ? unit.texCubeArrayBinding : &unit.defaultCubeArrayTex; |
| |
| if (texture->isImmutable()) |
| { |
| RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| ConstPixelBufferAccess dst(texture->getLevel(level)); |
| RC_IF_ERROR(storageFmt != dst.getFormat() || |
| width != dst.getWidth() || |
| height != dst.getHeight() || |
| depth != dst.getDepth(), GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| else |
| texture->allocLevel(level, storageFmt, width, height, depth); |
| |
| if (unpackPtr) |
| { |
| ConstPixelBufferAccess src = getUnpack3DAccess(transferFmt, width, height, depth, unpackPtr); |
| PixelBufferAccess dst (texture->getLevel(level)); |
| |
| if (isDstFloatDepthFormat) |
| depthValueFloatClampCopy(dst, src); |
| else |
| tcu::copy(dst, src); |
| } |
| else |
| { |
| // No data supplied, clear to initial |
| clearToTextureInitialValue(texture->getLevel(level)); |
| } |
| } |
| else |
| RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID); |
| } |
| |
| void ReferenceContext::texSubImage1D (deUint32 target, int level, int xoffset, int width, deUint32 format, deUint32 type, const void* data) |
| { |
| texSubImage2D(target, level, xoffset, 0, width, 1, format, type, data); |
| } |
| |
| void ReferenceContext::texSubImage2D (deUint32 target, int level, int xoffset, int yoffset, int width, int height, deUint32 format, deUint32 type, const void* data) |
| { |
| texSubImage3D(target, level, xoffset, yoffset, 0, width, height, 1, format, type, data); |
| } |
| |
| void ReferenceContext::texSubImage3D (deUint32 target, int level, int xoffset, int yoffset, int zoffset, int width, int height, int depth, deUint32 format, deUint32 type, const void* data) |
| { |
| TextureUnit& unit = m_textureUnits[m_activeTexture]; |
| |
| RC_IF_ERROR(xoffset < 0 || yoffset < 0 || zoffset < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(width < 0 || height < 0 || depth < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| |
| TextureFormat transferFmt = glu::mapGLTransferFormat(format, type); |
| RC_IF_ERROR(transferFmt.order == TextureFormat::CHANNELORDER_LAST || |
| transferFmt.type == TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| ConstPixelBufferAccess src = getUnpack3DAccess(transferFmt, width, height, depth, getPixelUnpackPtr(data)); |
| |
| if (target == GL_TEXTURE_1D && glu::isContextTypeGLCore(m_limits.contextType)) |
| { |
| Texture1D& texture = unit.tex1DBinding ? *unit.tex1DBinding : unit.default1DTex; |
| |
| RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| PixelBufferAccess dst = texture.getLevel(level); |
| |
| RC_IF_ERROR(xoffset + width > dst.getWidth() || |
| yoffset + height > dst.getHeight() || |
| zoffset + depth > dst.getDepth(), |
| GL_INVALID_VALUE, RC_RET_VOID); |
| |
| // depth components are limited to [0,1] range |
| if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS) |
| depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| else |
| tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| } |
| else if (target == GL_TEXTURE_2D) |
| { |
| Texture2D& texture = unit.tex2DBinding ? *unit.tex2DBinding : unit.default2DTex; |
| |
| RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| PixelBufferAccess dst = texture.getLevel(level); |
| |
| RC_IF_ERROR(xoffset + width > dst.getWidth() || |
| yoffset + height > dst.getHeight() || |
| zoffset + depth > dst.getDepth(), |
| GL_INVALID_VALUE, RC_RET_VOID); |
| |
| // depth components are limited to [0,1] range |
| if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS) |
| depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| else |
| tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| } |
| else if (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_X || |
| target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y || |
| target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z) |
| { |
| TextureCube& texture = unit.texCubeBinding ? *unit.texCubeBinding : unit.defaultCubeTex; |
| tcu::CubeFace face = mapGLCubeFace(target); |
| |
| RC_IF_ERROR(!texture.hasFace(level, face), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| PixelBufferAccess dst = texture.getFace(level, face); |
| |
| RC_IF_ERROR(xoffset + width > dst.getWidth() || |
| yoffset + height > dst.getHeight() || |
| zoffset + depth > dst.getDepth(), |
| GL_INVALID_VALUE, RC_RET_VOID); |
| |
| // depth components are limited to [0,1] range |
| if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS) |
| depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| else |
| tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| } |
| else if (target == GL_TEXTURE_3D) |
| { |
| Texture3D& texture = unit.tex3DBinding ? *unit.tex3DBinding : unit.default3DTex; |
| |
| RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| PixelBufferAccess dst = texture.getLevel(level); |
| |
| RC_IF_ERROR(xoffset + width > dst.getWidth() || |
| yoffset + height > dst.getHeight() || |
| zoffset + depth > dst.getDepth(), |
| GL_INVALID_VALUE, RC_RET_VOID); |
| |
| // depth components are limited to [0,1] range |
| if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS) |
| depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| else |
| tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| } |
| else if (target == GL_TEXTURE_2D_ARRAY) |
| { |
| Texture2DArray& texture = unit.tex2DArrayBinding ? *unit.tex2DArrayBinding : unit.default2DArrayTex; |
| |
| RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| PixelBufferAccess dst = texture.getLevel(level); |
| |
| RC_IF_ERROR(xoffset + width > dst.getWidth() || |
| yoffset + height > dst.getHeight() || |
| zoffset + depth > dst.getDepth(), |
| GL_INVALID_VALUE, RC_RET_VOID); |
| |
| // depth components are limited to [0,1] range |
| if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS) |
| depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| else |
| tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| } |
| else if (target == GL_TEXTURE_CUBE_MAP_ARRAY) |
| { |
| TextureCubeArray& texture = unit.texCubeArrayBinding ? *unit.texCubeArrayBinding : unit.defaultCubeArrayTex; |
| |
| RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| PixelBufferAccess dst = texture.getLevel(level); |
| |
| RC_IF_ERROR(xoffset + width > dst.getWidth() || |
| yoffset + height > dst.getHeight() || |
| zoffset + depth > dst.getDepth(), |
| GL_INVALID_VALUE, RC_RET_VOID); |
| |
| // depth components are limited to [0,1] range |
| if (dst.getFormat().order == tcu::TextureFormat::D || dst.getFormat().order == tcu::TextureFormat::DS) |
| depthValueFloatClampCopy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| else |
| tcu::copy(tcu::getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth), src); |
| } |
| else |
| RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID); |
| } |
| |
| void ReferenceContext::copyTexImage1D (deUint32 target, int level, deUint32 internalFormat, int x, int y, int width, int border) |
| { |
| TextureUnit& unit = m_textureUnits[m_activeTexture]; |
| TextureFormat storageFmt; |
| rr::MultisampleConstPixelBufferAccess src = getReadColorbuffer(); |
| |
| RC_IF_ERROR(border != 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(width < 0 || level < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(isEmpty(src), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| // Map storage format. |
| storageFmt = mapInternalFormat(internalFormat); |
| RC_IF_ERROR(storageFmt.order == TextureFormat::CHANNELORDER_LAST || |
| storageFmt.type == TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| if (target == GL_TEXTURE_1D) |
| { |
| // Validate size and level. |
| RC_IF_ERROR(width > m_limits.maxTexture2DSize, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| Texture1D* texture = unit.tex1DBinding ? unit.tex1DBinding : &unit.default1DTex; |
| |
| if (texture->isImmutable()) |
| { |
| RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| ConstPixelBufferAccess dst(texture->getLevel(level)); |
| RC_IF_ERROR(storageFmt != dst.getFormat() || |
| width != dst.getWidth(), GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| else |
| texture->allocLevel(level, storageFmt, width); |
| |
| // Copy from current framebuffer. |
| PixelBufferAccess dst = texture->getLevel(level); |
| for (int xo = 0; xo < width; xo++) |
| { |
| if (!de::inBounds(x+xo, 0, src.raw().getHeight())) |
| continue; // Undefined pixel. |
| |
| dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y), xo, 0); |
| } |
| } |
| else |
| RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID); |
| } |
| |
| void ReferenceContext::copyTexImage2D (deUint32 target, int level, deUint32 internalFormat, int x, int y, int width, int height, int border) |
| { |
| TextureUnit& unit = m_textureUnits[m_activeTexture]; |
| TextureFormat storageFmt; |
| rr::MultisampleConstPixelBufferAccess src = getReadColorbuffer(); |
| |
| RC_IF_ERROR(border != 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(width < 0 || height < 0 || level < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(isEmpty(src), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| // Map storage format. |
| storageFmt = mapInternalFormat(internalFormat); |
| RC_IF_ERROR(storageFmt.order == TextureFormat::CHANNELORDER_LAST || |
| storageFmt.type == TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| if (target == GL_TEXTURE_2D) |
| { |
| // Validate size and level. |
| RC_IF_ERROR(width > m_limits.maxTexture2DSize || height > m_limits.maxTexture2DSize, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| Texture2D* texture = unit.tex2DBinding ? unit.tex2DBinding : &unit.default2DTex; |
| |
| if (texture->isImmutable()) |
| { |
| RC_IF_ERROR(!texture->hasLevel(level), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| ConstPixelBufferAccess dst(texture->getLevel(level)); |
| RC_IF_ERROR(storageFmt != dst.getFormat() || |
| width != dst.getWidth() || |
| height != dst.getHeight(), GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| else |
| texture->allocLevel(level, storageFmt, width, height); |
| |
| // Copy from current framebuffer. |
| PixelBufferAccess dst = texture->getLevel(level); |
| for (int yo = 0; yo < height; yo++) |
| for (int xo = 0; xo < width; xo++) |
| { |
| if (!de::inBounds(x+xo, 0, src.raw().getHeight()) || !de::inBounds(y+yo, 0, src.raw().getDepth())) |
| continue; // Undefined pixel. |
| |
| dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y+yo), xo, yo); |
| } |
| } |
| else if (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_X || |
| target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y || |
| target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z) |
| { |
| // Validate size and level. |
| RC_IF_ERROR(width != height || width > m_limits.maxTextureCubeSize, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTextureCubeSize), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| TextureCube* texture = unit.texCubeBinding ? unit.texCubeBinding : &unit.defaultCubeTex; |
| tcu::CubeFace face = mapGLCubeFace(target); |
| |
| if (texture->isImmutable()) |
| { |
| RC_IF_ERROR(!texture->hasFace(level, face), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| ConstPixelBufferAccess dst(texture->getFace(level, face)); |
| RC_IF_ERROR(storageFmt != dst.getFormat() || |
| width != dst.getWidth() || |
| height != dst.getHeight(), GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| else |
| texture->allocFace(level, face, storageFmt, width, height); |
| |
| // Copy from current framebuffer. |
| PixelBufferAccess dst = texture->getFace(level, face); |
| for (int yo = 0; yo < height; yo++) |
| for (int xo = 0; xo < width; xo++) |
| { |
| if (!de::inBounds(x+xo, 0, src.raw().getHeight()) || !de::inBounds(y+yo, 0, src.raw().getDepth())) |
| continue; // Undefined pixel. |
| |
| dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y+yo), xo, yo); |
| } |
| } |
| else |
| RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID); |
| } |
| |
| void ReferenceContext::copyTexSubImage1D (deUint32 target, int level, int xoffset, int x, int y, int width) |
| { |
| TextureUnit& unit = m_textureUnits[m_activeTexture]; |
| rr::MultisampleConstPixelBufferAccess src = getReadColorbuffer(); |
| |
| RC_IF_ERROR(xoffset < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(width < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(isEmpty(src), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| if (target == GL_TEXTURE_1D) |
| { |
| Texture1D& texture = unit.tex1DBinding ? *unit.tex1DBinding : unit.default1DTex; |
| |
| RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| PixelBufferAccess dst = texture.getLevel(level); |
| |
| RC_IF_ERROR(xoffset + width > dst.getWidth(), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| for (int xo = 0; xo < width; xo++) |
| { |
| if (!de::inBounds(x+xo, 0, src.raw().getHeight())) |
| continue; |
| |
| dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y), xo+xoffset, 0); |
| } |
| } |
| else |
| RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID); |
| } |
| |
| void ReferenceContext::copyTexSubImage2D (deUint32 target, int level, int xoffset, int yoffset, int x, int y, int width, int height) |
| { |
| TextureUnit& unit = m_textureUnits[m_activeTexture]; |
| rr::MultisampleConstPixelBufferAccess src = getReadColorbuffer(); |
| |
| RC_IF_ERROR(xoffset < 0 || yoffset < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(width < 0 || height < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(isEmpty(src), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| if (target == GL_TEXTURE_2D) |
| { |
| Texture2D& texture = unit.tex2DBinding ? *unit.tex2DBinding : unit.default2DTex; |
| |
| RC_IF_ERROR(!texture.hasLevel(level), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| PixelBufferAccess dst = texture.getLevel(level); |
| |
| RC_IF_ERROR(xoffset + width > dst.getWidth() || |
| yoffset + height > dst.getHeight(), |
| GL_INVALID_VALUE, RC_RET_VOID); |
| |
| for (int yo = 0; yo < height; yo++) |
| for (int xo = 0; xo < width; xo++) |
| { |
| if (!de::inBounds(x+xo, 0, src.raw().getHeight()) || !de::inBounds(y+yo, 0, src.raw().getDepth())) |
| continue; |
| |
| dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y+yo), xo+xoffset, yo+yoffset); |
| } |
| } |
| else if (target == GL_TEXTURE_CUBE_MAP_NEGATIVE_X || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_X || |
| target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_Y || |
| target == GL_TEXTURE_CUBE_MAP_NEGATIVE_Z || |
| target == GL_TEXTURE_CUBE_MAP_POSITIVE_Z) |
| { |
| TextureCube& texture = unit.texCubeBinding ? *unit.texCubeBinding : unit.defaultCubeTex; |
| tcu::CubeFace face = mapGLCubeFace(target); |
| |
| RC_IF_ERROR(!texture.hasFace(level, face), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| PixelBufferAccess dst = texture.getFace(level, face); |
| |
| RC_IF_ERROR(xoffset + width > dst.getWidth() || |
| yoffset + height > dst.getHeight(), |
| GL_INVALID_VALUE, RC_RET_VOID); |
| |
| for (int yo = 0; yo < height; yo++) |
| for (int xo = 0; xo < width; xo++) |
| { |
| if (!de::inBounds(x+xo, 0, src.raw().getHeight()) || !de::inBounds(y+yo, 0, src.raw().getDepth())) |
| continue; |
| |
| dst.setPixel(rr::resolveMultisamplePixel(src, x+xo, y+yo), xo+xoffset, yo+yoffset); |
| } |
| } |
| else |
| RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID); |
| } |
| |
| void ReferenceContext::copyTexSubImage3D (deUint32 target, int level, int xoffset, int yoffset, int zoffset, int x, int y, int width, int height) |
| { |
| DE_UNREF(target && level && xoffset && yoffset && zoffset && x && y && width && height); |
| DE_ASSERT(false); |
| } |
| |
| void ReferenceContext::texStorage2D (deUint32 target, int levels, deUint32 internalFormat, int width, int height) |
| { |
| TextureUnit& unit = m_textureUnits[m_activeTexture]; |
| TextureFormat storageFmt; |
| |
| RC_IF_ERROR(width <= 0 || height <= 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(!de::inRange(levels, 1, (int)deLog2Floor32(de::max(width, height))+1), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| // Map storage format. |
| storageFmt = mapInternalFormat(internalFormat); |
| RC_IF_ERROR(storageFmt.order == TextureFormat::CHANNELORDER_LAST || |
| storageFmt.type == TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| if (target == GL_TEXTURE_2D) |
| { |
| Texture2D& texture = unit.tex2DBinding ? *unit.tex2DBinding : unit.default2DTex; |
| |
| RC_IF_ERROR(width > m_limits.maxTexture2DSize || height >= m_limits.maxTexture2DSize, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(texture.isImmutable(), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| texture.clearLevels(); |
| texture.setImmutable(); |
| |
| for (int level = 0; level < levels; level++) |
| { |
| int levelW = de::max(1, width >> level); |
| int levelH = de::max(1, height >> level); |
| |
| texture.allocLevel(level, storageFmt, levelW, levelH); |
| } |
| } |
| else if (target == GL_TEXTURE_CUBE_MAP) |
| { |
| TextureCube& texture = unit.texCubeBinding ? *unit.texCubeBinding : unit.defaultCubeTex; |
| |
| RC_IF_ERROR(width > m_limits.maxTextureCubeSize || height > m_limits.maxTextureCubeSize, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(texture.isImmutable(), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| texture.clearLevels(); |
| texture.setImmutable(); |
| |
| for (int level = 0; level < levels; level++) |
| { |
| int levelW = de::max(1, width >> level); |
| int levelH = de::max(1, height >> level); |
| |
| for (int face = 0; face < tcu::CUBEFACE_LAST; face++) |
| texture.allocFace(level, (tcu::CubeFace)face, storageFmt, levelW, levelH); |
| } |
| } |
| else |
| RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID); |
| } |
| |
| void ReferenceContext::texStorage3D (deUint32 target, int levels, deUint32 internalFormat, int width, int height, int depth) |
| { |
| TextureUnit& unit = m_textureUnits[m_activeTexture]; |
| TextureFormat storageFmt; |
| |
| RC_IF_ERROR(width <= 0 || height <= 0, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(!de::inRange(levels, 1, (int)deLog2Floor32(de::max(width, height))+1), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| // Map storage format. |
| storageFmt = mapInternalFormat(internalFormat); |
| RC_IF_ERROR(storageFmt.order == TextureFormat::CHANNELORDER_LAST || |
| storageFmt.type == TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| if (target == GL_TEXTURE_2D_ARRAY) |
| { |
| Texture2DArray& texture = unit.tex2DArrayBinding ? *unit.tex2DArrayBinding : unit.default2DArrayTex; |
| |
| RC_IF_ERROR(width > m_limits.maxTexture2DSize || |
| height >= m_limits.maxTexture2DSize || |
| depth >= m_limits.maxTexture2DArrayLayers, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(texture.isImmutable(), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| texture.clearLevels(); |
| texture.setImmutable(); |
| |
| for (int level = 0; level < levels; level++) |
| { |
| int levelW = de::max(1, width >> level); |
| int levelH = de::max(1, height >> level); |
| |
| texture.allocLevel(level, storageFmt, levelW, levelH, depth); |
| } |
| } |
| else if (target == GL_TEXTURE_3D) |
| { |
| Texture3D& texture = unit.tex3DBinding ? *unit.tex3DBinding : unit.default3DTex; |
| |
| RC_IF_ERROR(width > m_limits.maxTexture3DSize || |
| height > m_limits.maxTexture3DSize || |
| depth > m_limits.maxTexture3DSize, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(texture.isImmutable(), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| texture.clearLevels(); |
| texture.setImmutable(); |
| |
| for (int level = 0; level < levels; level++) |
| { |
| int levelW = de::max(1, width >> level); |
| int levelH = de::max(1, height >> level); |
| int levelD = de::max(1, depth >> level); |
| |
| texture.allocLevel(level, storageFmt, levelW, levelH, levelD); |
| } |
| } |
| else if (target == GL_TEXTURE_CUBE_MAP_ARRAY) |
| { |
| TextureCubeArray& texture = unit.texCubeArrayBinding ? *unit.texCubeArrayBinding : unit.defaultCubeArrayTex; |
| |
| RC_IF_ERROR(width != height || |
| depth % 6 != 0 || |
| width > m_limits.maxTexture2DSize || |
| depth >= m_limits.maxTexture2DArrayLayers, GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR(texture.isImmutable(), GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| texture.clearLevels(); |
| texture.setImmutable(); |
| |
| for (int level = 0; level < levels; level++) |
| { |
| int levelW = de::max(1, width >> level); |
| int levelH = de::max(1, height >> level); |
| |
| texture.allocLevel(level, storageFmt, levelW, levelH, depth); |
| } |
| } |
| else |
| RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID); |
| } |
| |
| // \todo [2014-02-19 pyry] Duplicated with code in gluTextureUtil.hpp |
| |
| static inline tcu::Sampler::WrapMode mapGLWrapMode (int value) |
| { |
| switch (value) |
| { |
| case GL_CLAMP_TO_EDGE: return tcu::Sampler::CLAMP_TO_EDGE; |
| case GL_REPEAT: return tcu::Sampler::REPEAT_GL; |
| case GL_MIRRORED_REPEAT: return tcu::Sampler::MIRRORED_REPEAT_GL; |
| default: return tcu::Sampler::WRAPMODE_LAST; |
| } |
| } |
| |
| static inline tcu::Sampler::FilterMode mapGLFilterMode (int value) |
| { |
| switch (value) |
| { |
| case GL_NEAREST: return tcu::Sampler::NEAREST; |
| case GL_LINEAR: return tcu::Sampler::LINEAR; |
| case GL_NEAREST_MIPMAP_NEAREST: return tcu::Sampler::NEAREST_MIPMAP_NEAREST; |
| case GL_NEAREST_MIPMAP_LINEAR: return tcu::Sampler::NEAREST_MIPMAP_LINEAR; |
| case GL_LINEAR_MIPMAP_NEAREST: return tcu::Sampler::LINEAR_MIPMAP_NEAREST; |
| case GL_LINEAR_MIPMAP_LINEAR: return tcu::Sampler::LINEAR_MIPMAP_LINEAR; |
| default: return tcu::Sampler::FILTERMODE_LAST; |
| } |
| } |
| |
| void ReferenceContext::texParameteri (deUint32 target, deUint32 pname, int value) |
| { |
| TextureUnit& unit = m_textureUnits[m_activeTexture]; |
| Texture* texture = DE_NULL; |
| |
| switch (target) |
| { |
| case GL_TEXTURE_1D: texture = unit.tex1DBinding ? unit.tex1DBinding : &unit.default1DTex; break; |
| case GL_TEXTURE_2D: texture = unit.tex2DBinding ? unit.tex2DBinding : &unit.default2DTex; break; |
| case GL_TEXTURE_CUBE_MAP: texture = unit.texCubeBinding ? unit.texCubeBinding : &unit.defaultCubeTex; break; |
| case GL_TEXTURE_2D_ARRAY: texture = unit.tex2DArrayBinding ? unit.tex2DArrayBinding : &unit.default2DArrayTex; break; |
| case GL_TEXTURE_3D: texture = unit.tex3DBinding ? unit.tex3DBinding : &unit.default3DTex; break; |
| case GL_TEXTURE_CUBE_MAP_ARRAY: texture = unit.texCubeArrayBinding ? unit.texCubeArrayBinding : &unit.defaultCubeArrayTex; break; |
| |
| default: RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID); |
| } |
| |
| switch (pname) |
| { |
| case GL_TEXTURE_WRAP_S: |
| { |
| tcu::Sampler::WrapMode wrapS = mapGLWrapMode(value); |
| RC_IF_ERROR(wrapS == tcu::Sampler::WRAPMODE_LAST, GL_INVALID_VALUE, RC_RET_VOID); |
| texture->getSampler().wrapS = wrapS; |
| break; |
| } |
| |
| case GL_TEXTURE_WRAP_T: |
| { |
| tcu::Sampler::WrapMode wrapT = mapGLWrapMode(value); |
| RC_IF_ERROR(wrapT == tcu::Sampler::WRAPMODE_LAST, GL_INVALID_VALUE, RC_RET_VOID); |
| texture->getSampler().wrapT = wrapT; |
| break; |
| } |
| |
| case GL_TEXTURE_WRAP_R: |
| { |
| tcu::Sampler::WrapMode wrapR = mapGLWrapMode(value); |
| RC_IF_ERROR(wrapR == tcu::Sampler::WRAPMODE_LAST, GL_INVALID_VALUE, RC_RET_VOID); |
| texture->getSampler().wrapR = wrapR; |
| break; |
| } |
| |
| case GL_TEXTURE_MIN_FILTER: |
| { |
| tcu::Sampler::FilterMode minMode = mapGLFilterMode(value); |
| RC_IF_ERROR(minMode == tcu::Sampler::FILTERMODE_LAST, GL_INVALID_VALUE, RC_RET_VOID); |
| texture->getSampler().minFilter = minMode; |
| break; |
| } |
| |
| case GL_TEXTURE_MAG_FILTER: |
| { |
| tcu::Sampler::FilterMode magMode = mapGLFilterMode(value); |
| RC_IF_ERROR(magMode != tcu::Sampler::LINEAR && magMode != tcu::Sampler::NEAREST, |
| GL_INVALID_VALUE, RC_RET_VOID); |
| texture->getSampler().magFilter = magMode; |
| break; |
| } |
| |
| case GL_TEXTURE_MAX_LEVEL: |
| { |
| RC_IF_ERROR(value < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| texture->setMaxLevel(value); |
| break; |
| } |
| |
| default: |
| RC_ERROR_RET(GL_INVALID_ENUM, RC_RET_VOID); |
| } |
| } |
| |
| static inline Framebuffer::AttachmentPoint mapGLAttachmentPoint (deUint32 attachment) |
| { |
| switch (attachment) |
| { |
| case GL_COLOR_ATTACHMENT0: return Framebuffer::ATTACHMENTPOINT_COLOR0; |
| case GL_DEPTH_ATTACHMENT: return Framebuffer::ATTACHMENTPOINT_DEPTH; |
| case GL_STENCIL_ATTACHMENT: return Framebuffer::ATTACHMENTPOINT_STENCIL; |
| default: return Framebuffer::ATTACHMENTPOINT_LAST; |
| } |
| } |
| |
| static inline Framebuffer::TexTarget mapGLFboTexTarget (deUint32 target) |
| { |
| switch (target) |
| { |
| case GL_TEXTURE_2D: return Framebuffer::TEXTARGET_2D; |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_X: return Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_X; |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: return Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_Y; |
| case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: return Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_Z; |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: return Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_X; |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: return Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Y; |
| case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: return Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Z; |
| default: return Framebuffer::TEXTARGET_LAST; |
| } |
| } |
| |
| void ReferenceContext::acquireFboAttachmentReference (const Framebuffer::Attachment& attachment) |
| { |
| switch (attachment.type) |
| { |
| case Framebuffer::ATTACHMENTTYPE_TEXTURE: |
| { |
| TCU_CHECK(attachment.name != 0); |
| Texture* texture = m_textures.find(attachment.name); |
| TCU_CHECK(texture); |
| m_textures.acquireReference(texture); |
| break; |
| } |
| |
| case Framebuffer::ATTACHMENTTYPE_RENDERBUFFER: |
| { |
| TCU_CHECK(attachment.name != 0); |
| Renderbuffer* rbo = m_renderbuffers.find(attachment.name); |
| TCU_CHECK(rbo); |
| m_renderbuffers.acquireReference(rbo); |
| break; |
| } |
| |
| default: |
| break; // Silently ignore |
| } |
| } |
| |
| void ReferenceContext::releaseFboAttachmentReference (const Framebuffer::Attachment& attachment) |
| { |
| switch (attachment.type) |
| { |
| case Framebuffer::ATTACHMENTTYPE_TEXTURE: |
| { |
| TCU_CHECK(attachment.name != 0); |
| Texture* texture = m_textures.find(attachment.name); |
| TCU_CHECK(texture); |
| m_textures.releaseReference(texture); |
| break; |
| } |
| |
| case Framebuffer::ATTACHMENTTYPE_RENDERBUFFER: |
| { |
| TCU_CHECK(attachment.name != 0); |
| Renderbuffer* rbo = m_renderbuffers.find(attachment.name); |
| TCU_CHECK(rbo); |
| m_renderbuffers.releaseReference(rbo); |
| break; |
| } |
| |
| default: |
| break; // Silently ignore |
| } |
| } |
| |
| void ReferenceContext::framebufferTexture2D (deUint32 target, deUint32 attachment, deUint32 textarget, deUint32 texture, int level) |
| { |
| if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) |
| { |
| // Attach to both depth and stencil. |
| framebufferTexture2D(target, GL_DEPTH_ATTACHMENT, textarget, texture, level); |
| framebufferTexture2D(target, GL_STENCIL_ATTACHMENT, textarget, texture, level); |
| } |
| else |
| { |
| Framebuffer::AttachmentPoint point = mapGLAttachmentPoint(attachment); |
| Texture* texObj = DE_NULL; |
| Framebuffer::TexTarget fboTexTarget = mapGLFboTexTarget(textarget); |
| |
| RC_IF_ERROR(target != GL_FRAMEBUFFER && |
| target != GL_DRAW_FRAMEBUFFER && |
| target != GL_READ_FRAMEBUFFER, GL_INVALID_ENUM, RC_RET_VOID); |
| RC_IF_ERROR(point == Framebuffer::ATTACHMENTPOINT_LAST, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| // Select binding point. |
| rc::Framebuffer* framebufferBinding = (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) ? m_drawFramebufferBinding : m_readFramebufferBinding; |
| RC_IF_ERROR(!framebufferBinding, GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| // If framebuffer object is bound for both reading and writing then we need to acquire/release multiple references. |
| int bindingRefCount = (framebufferBinding == m_drawFramebufferBinding ? 1 : 0) |
| + (framebufferBinding == m_readFramebufferBinding ? 1 : 0); |
| |
| if (texture != 0) |
| { |
| texObj = m_textures.find(texture); |
| |
| RC_IF_ERROR(!texObj, GL_INVALID_OPERATION, RC_RET_VOID); |
| RC_IF_ERROR(level != 0, GL_INVALID_VALUE, RC_RET_VOID); // \todo [2012-03-19 pyry] We should allow other levels as well. |
| |
| if (texObj->getType() == Texture::TYPE_2D) |
| RC_IF_ERROR(fboTexTarget != Framebuffer::TEXTARGET_2D, GL_INVALID_OPERATION, RC_RET_VOID); |
| else |
| { |
| TCU_CHECK(texObj->getType() == Texture::TYPE_CUBE_MAP); |
| if (!deInRange32(fboTexTarget, Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_X, Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Z)) |
| RC_ERROR_RET(GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| } |
| |
| Framebuffer::Attachment& fboAttachment = framebufferBinding->getAttachment(point); |
| for (int ndx = 0; ndx < bindingRefCount; ndx++) |
| releaseFboAttachmentReference(fboAttachment); |
| fboAttachment = Framebuffer::Attachment(); |
| |
| if (texObj) |
| { |
| fboAttachment.type = Framebuffer::ATTACHMENTTYPE_TEXTURE; |
| fboAttachment.name = texObj->getName(); |
| fboAttachment.texTarget = fboTexTarget; |
| fboAttachment.level = level; |
| |
| for (int ndx = 0; ndx < bindingRefCount; ndx++) |
| acquireFboAttachmentReference(fboAttachment); |
| } |
| } |
| } |
| |
| void ReferenceContext::framebufferTextureLayer (deUint32 target, deUint32 attachment, deUint32 texture, int level, int layer) |
| { |
| if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) |
| { |
| // Attach to both depth and stencil. |
| framebufferTextureLayer(target, GL_DEPTH_ATTACHMENT, texture, level, layer); |
| framebufferTextureLayer(target, GL_STENCIL_ATTACHMENT, texture, level, layer); |
| } |
| else |
| { |
| Framebuffer::AttachmentPoint point = mapGLAttachmentPoint(attachment); |
| Texture* texObj = DE_NULL; |
| |
| RC_IF_ERROR(target != GL_FRAMEBUFFER && |
| target != GL_DRAW_FRAMEBUFFER && |
| target != GL_READ_FRAMEBUFFER, GL_INVALID_ENUM, RC_RET_VOID); |
| RC_IF_ERROR(point == Framebuffer::ATTACHMENTPOINT_LAST, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| // Select binding point. |
| rc::Framebuffer* framebufferBinding = (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) ? m_drawFramebufferBinding : m_readFramebufferBinding; |
| RC_IF_ERROR(!framebufferBinding, GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| // If framebuffer object is bound for both reading and writing then we need to acquire/release multiple references. |
| int bindingRefCount = (framebufferBinding == m_drawFramebufferBinding ? 1 : 0) |
| + (framebufferBinding == m_readFramebufferBinding ? 1 : 0); |
| |
| if (texture != 0) |
| { |
| texObj = m_textures.find(texture); |
| |
| RC_IF_ERROR(!texObj, GL_INVALID_OPERATION, RC_RET_VOID); |
| RC_IF_ERROR(level != 0, GL_INVALID_VALUE, RC_RET_VOID); // \todo [2012-03-19 pyry] We should allow other levels as well. |
| |
| RC_IF_ERROR(texObj->getType() != Texture::TYPE_2D_ARRAY && |
| texObj->getType() != Texture::TYPE_3D && |
| texObj->getType() != Texture::TYPE_CUBE_MAP_ARRAY, GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| if (texObj->getType() == Texture::TYPE_2D_ARRAY || texObj->getType() == Texture::TYPE_CUBE_MAP_ARRAY) |
| { |
| RC_IF_ERROR((layer < 0) || (layer >= GL_MAX_ARRAY_TEXTURE_LAYERS), GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR((level < 0) || (level > deLog2Floor32(GL_MAX_TEXTURE_SIZE)),GL_INVALID_VALUE, RC_RET_VOID); |
| } |
| else if (texObj->getType() == Texture::TYPE_3D) |
| { |
| RC_IF_ERROR((layer < 0) || (layer >= GL_MAX_3D_TEXTURE_SIZE), GL_INVALID_VALUE, RC_RET_VOID); |
| RC_IF_ERROR((level < 0) || (level > deLog2Floor32(GL_MAX_3D_TEXTURE_SIZE)), GL_INVALID_VALUE, RC_RET_VOID); |
| } |
| } |
| |
| Framebuffer::Attachment& fboAttachment = framebufferBinding->getAttachment(point); |
| for (int ndx = 0; ndx < bindingRefCount; ndx++) |
| releaseFboAttachmentReference(fboAttachment); |
| fboAttachment = Framebuffer::Attachment(); |
| |
| if (texObj) |
| { |
| fboAttachment.type = Framebuffer::ATTACHMENTTYPE_TEXTURE; |
| fboAttachment.name = texObj->getName(); |
| fboAttachment.texTarget = texLayeredTypeToTarget(texObj->getType()); |
| fboAttachment.level = level; |
| fboAttachment.layer = layer; |
| |
| DE_ASSERT(fboAttachment.texTarget != Framebuffer::TEXTARGET_LAST); |
| |
| for (int ndx = 0; ndx < bindingRefCount; ndx++) |
| acquireFboAttachmentReference(fboAttachment); |
| } |
| } |
| } |
| |
| void ReferenceContext::framebufferRenderbuffer (deUint32 target, deUint32 attachment, deUint32 renderbuffertarget, deUint32 renderbuffer) |
| { |
| if (attachment == GL_DEPTH_STENCIL_ATTACHMENT) |
| { |
| // Attach both to depth and stencil. |
| framebufferRenderbuffer(target, GL_DEPTH_ATTACHMENT, renderbuffertarget, renderbuffer); |
| framebufferRenderbuffer(target, GL_STENCIL_ATTACHMENT, renderbuffertarget, renderbuffer); |
| } |
| else |
| { |
| Framebuffer::AttachmentPoint point = mapGLAttachmentPoint(attachment); |
| Renderbuffer* rbo = DE_NULL; |
| |
| RC_IF_ERROR(target != GL_FRAMEBUFFER && |
| target != GL_DRAW_FRAMEBUFFER && |
| target != GL_READ_FRAMEBUFFER, GL_INVALID_ENUM, RC_RET_VOID); |
| RC_IF_ERROR(point == Framebuffer::ATTACHMENTPOINT_LAST, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| // Select binding point. |
| rc::Framebuffer* framebufferBinding = (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) ? m_drawFramebufferBinding : m_readFramebufferBinding; |
| RC_IF_ERROR(!framebufferBinding, GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| // If framebuffer object is bound for both reading and writing then we need to acquire/release multiple references. |
| int bindingRefCount = (framebufferBinding == m_drawFramebufferBinding ? 1 : 0) |
| + (framebufferBinding == m_readFramebufferBinding ? 1 : 0); |
| |
| if (renderbuffer != 0) |
| { |
| rbo = m_renderbuffers.find(renderbuffer); |
| |
| RC_IF_ERROR(renderbuffertarget != GL_RENDERBUFFER, GL_INVALID_ENUM, RC_RET_VOID); |
| RC_IF_ERROR(!rbo, GL_INVALID_OPERATION, RC_RET_VOID); |
| } |
| |
| Framebuffer::Attachment& fboAttachment = framebufferBinding->getAttachment(point); |
| for (int ndx = 0; ndx < bindingRefCount; ndx++) |
| releaseFboAttachmentReference(fboAttachment); |
| fboAttachment = Framebuffer::Attachment(); |
| |
| if (rbo) |
| { |
| fboAttachment.type = Framebuffer::ATTACHMENTTYPE_RENDERBUFFER; |
| fboAttachment.name = rbo->getName(); |
| |
| for (int ndx = 0; ndx < bindingRefCount; ndx++) |
| acquireFboAttachmentReference(fboAttachment); |
| } |
| } |
| } |
| |
| deUint32 ReferenceContext::checkFramebufferStatus (deUint32 target) |
| { |
| RC_IF_ERROR(target != GL_FRAMEBUFFER && |
| target != GL_DRAW_FRAMEBUFFER && |
| target != GL_READ_FRAMEBUFFER, GL_INVALID_ENUM, 0); |
| |
| // Select binding point. |
| rc::Framebuffer* framebufferBinding = (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER) ? m_drawFramebufferBinding : m_readFramebufferBinding; |
| |
| // Default framebuffer is always complete. |
| if (!framebufferBinding) |
| return GL_FRAMEBUFFER_COMPLETE; |
| |
| int width = -1; |
| int height = -1; |
| bool hasAttachment = false; |
| bool attachmentComplete = true; |
| bool dimensionsOk = true; |
| |
| for (int point = 0; point < Framebuffer::ATTACHMENTPOINT_LAST; point++) |
| { |
| const Framebuffer::Attachment& attachment = framebufferBinding->getAttachment((Framebuffer::AttachmentPoint)point); |
| int attachmentWidth = 0; |
| int attachmentHeight = 0; |
| tcu::TextureFormat attachmentFormat; |
| |
| if (attachment.type == Framebuffer::ATTACHMENTTYPE_TEXTURE) |
| { |
| const Texture* texture = m_textures.find(attachment.name); |
| tcu::ConstPixelBufferAccess level; |
| TCU_CHECK(texture); |
| |
| if (attachment.texTarget == Framebuffer::TEXTARGET_2D) |
| { |
| DE_ASSERT(texture->getType() == Texture::TYPE_2D); |
| const Texture2D* tex2D = static_cast<const Texture2D*>(texture); |
| |
| if (tex2D->hasLevel(attachment.level)) |
| level = tex2D->getLevel(attachment.level); |
| } |
| else if (deInRange32(attachment.texTarget, Framebuffer::TEXTARGET_CUBE_MAP_POSITIVE_X, |
| Framebuffer::TEXTARGET_CUBE_MAP_NEGATIVE_Z)) |
| { |
| DE_ASSERT(texture->getType() == Texture::TYPE_CUBE_MAP); |
| |
| const TextureCube* texCube = static_cast<const TextureCube*>(texture); |
| const tcu::CubeFace face = texTargetToFace(attachment.texTarget); |
| TCU_CHECK(de::inBounds<int>(face, 0, tcu::CUBEFACE_LAST)); |
| |
| if (texCube->hasFace(attachment.level, face)) |
| level = texCube->getFace(attachment.level, face); |
| } |
| else if (attachment.texTarget == Framebuffer::TEXTARGET_2D_ARRAY) |
| { |
| DE_ASSERT(texture->getType() == Texture::TYPE_2D_ARRAY); |
| const Texture2DArray* tex2DArr = static_cast<const Texture2DArray*>(texture); |
| |
| if (tex2DArr->hasLevel(attachment.level)) |
| level = tex2DArr->getLevel(attachment.level); // \note Slice doesn't matter here. |
| } |
| else if (attachment.texTarget == Framebuffer::TEXTARGET_3D) |
| { |
| DE_ASSERT(texture->getType() == Texture::TYPE_3D); |
| const Texture3D* tex3D = static_cast<const Texture3D*>(texture); |
| |
| if (tex3D->hasLevel(attachment.level)) |
| level = tex3D->getLevel(attachment.level); // \note Slice doesn't matter here. |
| } |
| else if (attachment.texTarget == Framebuffer::TEXTARGET_CUBE_MAP_ARRAY) |
| { |
| DE_ASSERT(texture->getType() == Texture::TYPE_CUBE_MAP_ARRAY); |
| const TextureCubeArray* texCubeArr = static_cast<const TextureCubeArray*>(texture); |
| |
| if (texCubeArr->hasLevel(attachment.level)) |
| level = texCubeArr->getLevel(attachment.level); // \note Slice doesn't matter here. |
| } |
| else |
| TCU_FAIL("Framebuffer attached to a texture but no valid target specified"); |
| |
| attachmentWidth = level.getWidth(); |
| attachmentHeight = level.getHeight(); |
| attachmentFormat = level.getFormat(); |
| } |
| else if (attachment.type == Framebuffer::ATTACHMENTTYPE_RENDERBUFFER) |
| { |
| const Renderbuffer* renderbuffer = m_renderbuffers.find(attachment.name); |
| TCU_CHECK(renderbuffer); |
| |
| attachmentWidth = renderbuffer->getWidth(); |
| attachmentHeight = renderbuffer->getHeight(); |
| attachmentFormat = renderbuffer->getFormat(); |
| } |
| else |
| { |
| TCU_CHECK(attachment.type == Framebuffer::ATTACHMENTTYPE_LAST); |
| continue; // Skip rest of checks. |
| } |
| |
| if (!hasAttachment && attachmentWidth > 0 && attachmentHeight > 0) |
| { |
| width = attachmentWidth; |
| height = attachmentHeight; |
| hasAttachment = true; |
| } |
| else if (attachmentWidth != width || attachmentHeight != height) |
| dimensionsOk = false; |
| |
| // Validate attachment point compatibility. |
| switch (attachmentFormat.order) |
| { |
| case TextureFormat::R: |
| case TextureFormat::RG: |
| case TextureFormat::RGB: |
| case TextureFormat::RGBA: |
| case TextureFormat::sRGB: |
| case TextureFormat::sRGBA: |
| if (point != Framebuffer::ATTACHMENTPOINT_COLOR0) |
| attachmentComplete = false; |
| break; |
| |
| case TextureFormat::D: |
| if (point != Framebuffer::ATTACHMENTPOINT_DEPTH) |
| attachmentComplete = false; |
| break; |
| |
| case TextureFormat::S: |
| if (point != Framebuffer::ATTACHMENTPOINT_STENCIL) |
| attachmentComplete = false; |
| break; |
| |
| case TextureFormat::DS: |
| if (point != Framebuffer::ATTACHMENTPOINT_DEPTH && |
| point != Framebuffer::ATTACHMENTPOINT_STENCIL) |
| attachmentComplete = false; |
| break; |
| |
| default: |
| TCU_FAIL("Unsupported attachment channel order"); |
| } |
| } |
| |
| if (!attachmentComplete) |
| return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; |
| else if (!hasAttachment) |
| return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT; |
| else if (!dimensionsOk) |
| return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; |
| else |
| return GL_FRAMEBUFFER_COMPLETE; |
| } |
| |
| void ReferenceContext::getFramebufferAttachmentParameteriv (deUint32 target, deUint32 attachment, deUint32 pname, int* params) |
| { |
| DE_UNREF(target && attachment && pname && params); |
| TCU_CHECK(false); // \todo [pyry] Implement |
| } |
| |
| void ReferenceContext::renderbufferStorage (deUint32 target, deUint32 internalformat, int width, int height) |
| { |
| TextureFormat format = glu::mapGLInternalFormat(internalformat); |
| |
| RC_IF_ERROR(target != GL_RENDERBUFFER, GL_INVALID_ENUM, RC_RET_VOID); |
| RC_IF_ERROR(!m_renderbufferBinding, GL_INVALID_OPERATION, RC_RET_VOID); |
| RC_IF_ERROR(!deInRange32(width, 0, m_limits.maxRenderbufferSize) || |
| !deInRange32(height, 0, m_limits.maxRenderbufferSize), |
| GL_INVALID_OPERATION, RC_RET_VOID); |
| RC_IF_ERROR(format.order == TextureFormat::CHANNELORDER_LAST || |
| format.type == TextureFormat::CHANNELTYPE_LAST, GL_INVALID_ENUM, RC_RET_VOID); |
| |
| m_renderbufferBinding->setStorage(format, (int)width, (int)height); |
| } |
| |
| void ReferenceContext::renderbufferStorageMultisample (deUint32 target, int samples, deUint32 internalFormat, int width, int height) |
| { |
| // \todo [2012-04-07 pyry] Implement MSAA support. |
| DE_UNREF(samples); |
| renderbufferStorage(target, internalFormat, width, height); |
| } |
| |
| tcu::PixelBufferAccess ReferenceContext::getFboAttachment (const rc::Framebuffer& framebuffer, rc::Framebuffer::AttachmentPoint point) |
| { |
| const Framebuffer::Attachment& attachment = framebuffer.getAttachment(point); |
| |
| switch (attachment.type) |
| { |
| case Framebuffer::ATTACHMENTTYPE_TEXTURE: |
| { |
| Texture* texture = m_textures.find(attachment.name); |
| TCU_CHECK(texture); |
| |
| if (texture->getType() == Texture::TYPE_2D) |
| return dynamic_cast<Texture2D*>(texture)->getLevel(attachment.level); |
| else if (texture->getType() == Texture::TYPE_CUBE_MAP) |
| return dynamic_cast<TextureCube*>(texture)->getFace(attachment.level, texTargetToFace(attachment.texTarget)); |
| else if (texture->getType() == Texture::TYPE_2D_ARRAY || |
| texture->getType() == Texture::TYPE_3D || |
| texture->getType() == Texture::TYPE_CUBE_MAP_ARRAY) |
| { |
| tcu::PixelBufferAccess level; |
| |
| if (texture->getType() == Texture::TYPE_2D_ARRAY) |
| level = dynamic_cast<Texture2DArray*>(texture)->getLevel(attachment.level); |
| else if (texture->getType() == Texture::TYPE_3D) |
| level = dynamic_cast<Texture3D*>(texture)->getLevel(attachment.level); |
| else if (texture->getType() == Texture::TYPE_CUBE_MAP_ARRAY) |
| level = dynamic_cast<TextureCubeArray*>(texture)->getLevel(attachment.level); |
| |
| void* layerData = static_cast<deUint8*>(level.getDataPtr()) + level.getSlicePitch() * attachment.layer; |
| |
| return tcu::PixelBufferAccess(level.getFormat(), level.getWidth(), level.getHeight(), 1, level.getRowPitch(), 0, layerData); |
| } |
| else |
| return nullAccess(); |
| } |
| |
| case Framebuffer::ATTACHMENTTYPE_RENDERBUFFER: |
| { |
| Renderbuffer* rbo = m_renderbuffers.find(attachment.name); |
| TCU_CHECK(rbo); |
| |
| return rbo->getAccess(); |
| } |
| |
| default: |
| return nullAccess(); |
| } |
| } |
| |
| const Texture2D& ReferenceContext::getTexture2D (int unitNdx) const |
| { |
| const TextureUnit& unit = m_textureUnits[unitNdx]; |
| return unit.tex2DBinding ? *unit.tex2DBinding : unit.default2DTex; |
| } |
| |
| const TextureCube& ReferenceContext::getTextureCube (int unitNdx) const |
| { |
| const TextureUnit& unit = m_textureUnits[unitNdx]; |
| return unit.texCubeBinding ? *unit.texCubeBinding : unit.defaultCubeTex; |
| } |
| |
| static bool isValidBufferTarget (deUint32 target) |
| { |
| switch (target) |
| { |
| case GL_ARRAY_BUFFER: |
| case GL_COPY_READ_BUFFER: |
| case GL_COPY_WRITE_BUFFER: |
| case GL_DRAW_INDIRECT_BUFFER: |
| case GL_ELEMENT_ARRAY_BUFFER: |
| case GL_PIXEL_PACK_BUFFER: |
| case GL_PIXEL_UNPACK_BUFFER: |
| case GL_TRANSFORM_FEEDBACK_BUFFER: |
| case GL_UNIFORM_BUFFER: |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| |
| void ReferenceContext::setBufferBinding (deUint32 target, DataBuffer* buffer) |
| { |
| DataBuffer** bindingPoint = DE_NULL; |
| VertexArray* vertexArrayObject = (m_vertexArrayBinding) ? (m_vertexArrayBinding) : (&m_clientVertexArray); |
| |
| switch (target) |
| { |
| case GL_ARRAY_BUFFER: bindingPoint = &m_arrayBufferBinding; break; |
| case GL_COPY_READ_BUFFER: bindingPoint = &m_copyReadBufferBinding; break; |
| case GL_COPY_WRITE_BUFFER: bindingPoint = &m_copyWriteBufferBinding; break; |
| case GL_DRAW_INDIRECT_BUFFER: bindingPoint = &m_drawIndirectBufferBinding; break; |
| case GL_ELEMENT_ARRAY_BUFFER: bindingPoint = &vertexArrayObject->m_elementArrayBufferBinding; break; |
| case GL_PIXEL_PACK_BUFFER: bindingPoint = &m_pixelPackBufferBinding; break; |
| case GL_PIXEL_UNPACK_BUFFER: bindingPoint = &m_pixelUnpackBufferBinding; break; |
| case GL_TRANSFORM_FEEDBACK_BUFFER: bindingPoint = &m_transformFeedbackBufferBinding; break; |
| case GL_UNIFORM_BUFFER: bindingPoint = &m_uniformBufferBinding; break; |
| default: |
| DE_ASSERT(false); |
| return; |
| } |
| |
| if (*bindingPoint) |
| { |
| m_buffers.releaseReference(*bindingPoint); |
| *bindingPoint = DE_NULL; |
| } |
| |
| if (buffer) |
| m_buffers.acquireReference(buffer); |
| |
| *bindingPoint = buffer; |
| } |
| |
| DataBuffer* ReferenceContext::getBufferBinding (deUint32 target) const |
| { |
| const VertexArray* vertexArrayObject = (m_vertexArrayBinding) ? (m_vertexArrayBinding) : (&m_clientVertexArray); |
| |
| switch (target) |
| { |
| case GL_ARRAY_BUFFER: return m_arrayBufferBinding; |
| case GL_COPY_READ_BUFFER: return m_copyReadBufferBinding; |
| case GL_COPY_WRITE_BUFFER: return m_copyWriteBufferBinding; |
| case GL_DRAW_INDIRECT_BUFFER: return m_drawIndirectBufferBinding; |
| case GL_ELEMENT_ARRAY_BUFFER: return vertexArrayObject->m_elementArrayBufferBinding; |
| case GL_PIXEL_PACK_BUFFER: return m_pixelPackBufferBinding; |
| case GL_PIXEL_UNPACK_BUFFER: return m_pixelUnpackBufferBinding; |
| case GL_TRANSFORM_FEEDBACK_BUFFER: return m_transformFeedbackBufferBinding; |
| case GL_UNIFORM_BUFFER: return m_uniformBufferBinding; |
| default: |
| DE_ASSERT(false); |
| return DE_NULL; |
| } |
| } |
| |
| void ReferenceContext::bindBuffer (deUint32 target, deUint32 buffer) |
| { |
| RC_IF_ERROR(!isValidBufferTarget(target), GL_INVALID_ENUM, RC_RET_VOID); |
| |
| rc::DataBuffer* bufObj = DE_NULL; |
| |
| if (buffer != 0) |
| { |
| bufObj = m_buffers.find(buffer); |
| if (!bufObj) |
| { |
| bufObj = new DataBuffer(buffer); |
| m_buffers.insert(bufObj); |
| } |
| } |
| |
| setBufferBinding(target, bufObj); |
| } |
| |
| void ReferenceContext::genBuffers (int numBuffers, deUint32* buffers) |
| { |
| RC_IF_ERROR(!buffers, GL_INVALID_VALUE, RC_RET_VOID); |
| |
| for (int ndx = 0; ndx < numBuffers; ndx++) |
| buffers[ndx] = m_buffers.allocateName(); |
| } |
| |
| void ReferenceContext::deleteBuffers (int numBuffers, const deUint32* buffers) |
| { |
| RC_IF_ERROR(numBuffers < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| |
| for (int ndx = 0; ndx < numBuffers; ndx++) |
| { |
| deUint32 buffer = buffers[ndx]; |
| DataBuffer* bufObj = DE_NULL; |
| |
| if (buffer == 0) |
| continue; |
| |
| bufObj = m_buffers.find(buffer); |
| |
| if (bufObj) |
| deleteBuffer(bufObj); |
| } |
| } |
| |
| void ReferenceContext::deleteBuffer (DataBuffer* buffer) |
| { |
| static const deUint32 bindingPoints[] = |
| { |
| GL_ARRAY_BUFFER, |
| GL_COPY_READ_BUFFER, |
| GL_COPY_WRITE_BUFFER, |
| GL_DRAW_INDIRECT_BUFFER, |
| GL_ELEMENT_ARRAY_BUFFER, |
| GL_PIXEL_PACK_BUFFER, |
| GL_PIXEL_UNPACK_BUFFER, |
| GL_TRANSFORM_FEEDBACK_BUFFER, |
| GL_UNIFORM_BUFFER |
| }; |
| |
| for (int bindingNdx = 0; bindingNdx < DE_LENGTH_OF_ARRAY(bindingPoints); bindingNdx++) |
| { |
| if (getBufferBinding(bindingPoints[bindingNdx]) == buffer) |
| setBufferBinding(bindingPoints[bindingNdx], DE_NULL); |
| } |
| |
| { |
| vector<VertexArray*> vertexArrays; |
| m_vertexArrays.getAll(vertexArrays); |
| vertexArrays.push_back(&m_clientVertexArray); |
| |
| for (vector<VertexArray*>::iterator i = vertexArrays.begin(); i != vertexArrays.end(); i++) |
| { |
| if ((*i)->m_elementArrayBufferBinding == buffer) |
| { |
| m_buffers.releaseReference(buffer); |
| (*i)->m_elementArrayBufferBinding = DE_NULL; |
| } |
| |
| for (size_t vertexAttribNdx = 0; vertexAttribNdx < (*i)->m_arrays.size(); ++vertexAttribNdx) |
| { |
| if ((*i)->m_arrays[vertexAttribNdx].bufferBinding == buffer) |
| { |
| m_buffers.releaseReference(buffer); |
| (*i)->m_arrays[vertexAttribNdx].bufferDeleted = true; |
| (*i)->m_arrays[vertexAttribNdx].bufferBinding = DE_NULL; |
| } |
| } |
| } |
| } |
| |
| DE_ASSERT(buffer->getRefCount() == 1); |
| m_buffers.releaseReference(buffer); |
| } |
| |
| void ReferenceContext::bufferData (deUint32 target, deIntptr size, const void* data, deUint32 usage) |
| { |
| RC_IF_ERROR(!isValidBufferTarget(target), GL_INVALID_ENUM, RC_RET_VOID); |
| RC_IF_ERROR(size < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| |
| DE_UNREF(usage); |
| |
| DataBuffer* buffer = getBufferBinding(target); |
| RC_IF_ERROR(!buffer, GL_INVALID_OPERATION, RC_RET_VOID); |
| |
| DE_ASSERT((deIntptr)(int)size == size); |
| buffer->setStorage((int)size); |
| if (data) |
| deMemcpy(buffer->getData(), data, (int)size); |
| } |
| |
| void ReferenceContext::bufferSubData (deUint32 target, deIntptr offset, deIntptr size, const void* data) |
| { |
| RC_IF_ERROR(!isValidBufferTarget(target), GL_INVALID_ENUM, RC_RET_VOID); |
| RC_IF_ERROR(offset < 0 || size < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| |
| DataBuffer* buffer = getBufferBinding(target); |
| |
| RC_IF_ERROR(!buffer, GL_INVALID_OPERATION, RC_RET_VOID); |
| RC_IF_ERROR((int)(offset+size) > buffer->getSize(), GL_INVALID_VALUE, RC_RET_VOID); |
| |
| deMemcpy(buffer->getData()+offset, data, (int)size); |
| } |
| |
| void ReferenceContext::clearColor (float red, float green, float blue, float alpha) |
| { |
| m_clearColor = Vec4(de::clamp(red, 0.0f, 1.0f), |
| de::clamp(green, 0.0f, 1.0f), |
| de::clamp(blue, 0.0f, 1.0f), |
| de::clamp(alpha, 0.0f, 1.0f)); |
| } |
| |
| void ReferenceContext::clearDepthf (float depth) |
| { |
| m_clearDepth = de::clamp(depth, 0.0f, 1.0f); |
| } |
| |
| void ReferenceContext::clearStencil (int stencil) |
| { |
| m_clearStencil = stencil; |
| } |
| |
| void ReferenceContext::scissor (int x, int y, int width, int height) |
| { |
| RC_IF_ERROR(width < 0 || height < 0, GL_INVALID_VALUE, RC_RET_VOID); |
| m_scissorBox = IVec4(x, y, width, height); |
| } |
| |
| void ReferenceContext::enable (deUint32 cap) |
| { |
| switch (cap) |
| { |
| case GL_BLEND: m_blendEnabled = true; break; |
| case GL_SCISSOR_TEST: m_scissorEnabled = true; break; |
| case GL_DEPTH_TEST: m_depthTestEnabled = true; break; |
| case GL_STENCIL_TEST: m_stencilTestEnabled = true; break; |
| case GL_POLYGON_OFFSET_FILL: m_polygonOffsetFillEnabled = true; break; |
| |
| case GL_FRAMEBUFFER_SRGB: |
| if (glu::isContextTypeGLCore(getType())) |
| { |
| m_sRGBUpdateEnabled = true; |
| break; |
| } |
| setError(GL_INVALID_ENUM); |
| break; |
| |
| case GL_DEPTH_CLAMP: |
| if (glu::isContextTypeGLCore(getType())) |
| { |
| m_depthClampEnabled = true; |
| break; |
| } |
| setError(GL_INVALID_ENUM); |
| break; |
| |
| case GL_DITHER: |
| // Not implemented - just ignored. |
| break; |
| |
| case GL_PRIMITIVE_RESTART_FIXED_INDEX: |
| if (!glu::isContextTypeGLCore(getType())) |
| { |
| m_primitiveRestartFixedIndex = true; |
| break; |
| } |
| setError(GL_INVALID_ENUM); |
| break; |
| |
| case GL_PRIMITIVE_RESTART: |
| if (glu::isContextTypeGLCore(getType())) |
| |