mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-08-02 04:41:08 +00:00
2099 lines
72 KiB
C++
2099 lines
72 KiB
C++
/******************************************************************************
|
|
* The MIT License (MIT)
|
|
*
|
|
* Copyright (c) 2015-2019 Baldur Karlsson
|
|
* Copyright (c) 2014 Crytek
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
******************************************************************************/
|
|
|
|
#include "gl_renderstate.h"
|
|
#include "gl_driver.h"
|
|
|
|
struct EnableDisableCap
|
|
{
|
|
GLenum cap;
|
|
rdcliteral name;
|
|
};
|
|
|
|
static const EnableDisableCap enable_disable_cap[] = {
|
|
{eGL_CLIP_DISTANCE0, "GL_CLIP_DISTANCE0"_lit},
|
|
{eGL_CLIP_DISTANCE1, "GL_CLIP_DISTANCE1"_lit},
|
|
{eGL_CLIP_DISTANCE2, "GL_CLIP_DISTANCE2"_lit},
|
|
{eGL_CLIP_DISTANCE3, "GL_CLIP_DISTANCE3"_lit},
|
|
{eGL_CLIP_DISTANCE4, "GL_CLIP_DISTANCE4"_lit},
|
|
{eGL_CLIP_DISTANCE5, "GL_CLIP_DISTANCE5"_lit},
|
|
{eGL_CLIP_DISTANCE6, "GL_CLIP_DISTANCE6"_lit},
|
|
{eGL_CLIP_DISTANCE7, "GL_CLIP_DISTANCE7"_lit},
|
|
{eGL_COLOR_LOGIC_OP, "GL_COLOR_LOGIC_OP"_lit},
|
|
{eGL_CULL_FACE, "GL_CULL_FACE"_lit},
|
|
{eGL_DEPTH_CLAMP, "GL_DEPTH_CLAMP"_lit},
|
|
{eGL_DEPTH_TEST, "GL_DEPTH_TEST"_lit},
|
|
{eGL_DEPTH_BOUNDS_TEST_EXT, "GL_DEPTH_BOUNDS_TEST_EXT"_lit},
|
|
{eGL_DITHER, "GL_DITHER"_lit},
|
|
{eGL_FRAMEBUFFER_SRGB, "GL_FRAMEBUFFER_SRGB"_lit},
|
|
{eGL_LINE_SMOOTH, "GL_LINE_SMOOTH"_lit},
|
|
{eGL_MULTISAMPLE, "GL_MULTISAMPLE"_lit},
|
|
{eGL_POLYGON_SMOOTH, "GL_POLYGON_SMOOTH"_lit},
|
|
{eGL_POLYGON_OFFSET_FILL, "GL_POLYGON_OFFSET_FILL"_lit},
|
|
{eGL_POLYGON_OFFSET_LINE, "GL_POLYGON_OFFSET_LINE"_lit},
|
|
{eGL_POLYGON_OFFSET_POINT, "GL_POLYGON_OFFSET_POINT"_lit},
|
|
{eGL_PROGRAM_POINT_SIZE, "GL_PROGRAM_POINT_SIZE"_lit},
|
|
{eGL_PRIMITIVE_RESTART, "GL_PRIMITIVE_RESTART"_lit},
|
|
{eGL_PRIMITIVE_RESTART_FIXED_INDEX, "GL_PRIMITIVE_RESTART_FIXED_INDEX"_lit},
|
|
{eGL_SAMPLE_ALPHA_TO_COVERAGE, "GL_SAMPLE_ALPHA_TO_COVERAGE"_lit},
|
|
{eGL_SAMPLE_ALPHA_TO_ONE, "GL_SAMPLE_ALPHA_TO_ONE"_lit},
|
|
{eGL_SAMPLE_COVERAGE, "GL_SAMPLE_COVERAGE"_lit},
|
|
{eGL_SAMPLE_MASK, "GL_SAMPLE_MASK"_lit},
|
|
{eGL_SAMPLE_SHADING, "GL_SAMPLE_SHADING"_lit},
|
|
{eGL_RASTER_MULTISAMPLE_EXT, "GL_RASTER_MULTISAMPLE_EXT"_lit},
|
|
{eGL_STENCIL_TEST, "GL_STENCIL_TEST"_lit},
|
|
{eGL_TEXTURE_CUBE_MAP_SEAMLESS, "GL_TEXTURE_CUBE_MAP_SEAMLESS"_lit},
|
|
{eGL_BLEND_ADVANCED_COHERENT_KHR, "GL_BLEND_ADVANCED_COHERENT_KHR"_lit},
|
|
{eGL_RASTERIZER_DISCARD, "GL_RASTERIZER_DISCARD"_lit},
|
|
};
|
|
|
|
void ResetPixelPackState(bool compressed, GLint alignment)
|
|
{
|
|
PixelPackState empty;
|
|
empty.alignment = alignment;
|
|
empty.Apply(compressed);
|
|
}
|
|
|
|
void ResetPixelUnpackState(bool compressed, GLint alignment)
|
|
{
|
|
PixelUnpackState empty;
|
|
empty.alignment = alignment;
|
|
empty.Apply(compressed);
|
|
}
|
|
|
|
PixelStorageState::PixelStorageState()
|
|
: swapBytes(),
|
|
lsbFirst(),
|
|
rowlength(),
|
|
imageheight(),
|
|
skipPixels(),
|
|
skipRows(),
|
|
skipImages(),
|
|
alignment(),
|
|
compressedBlockWidth(),
|
|
compressedBlockHeight(),
|
|
compressedBlockDepth(),
|
|
compressedBlockSize()
|
|
{
|
|
}
|
|
|
|
void PixelPackState::Fetch(bool compressed)
|
|
{
|
|
if(!IsGLES)
|
|
{
|
|
GL.glGetIntegerv(eGL_PACK_SWAP_BYTES, &swapBytes);
|
|
GL.glGetIntegerv(eGL_PACK_LSB_FIRST, &lsbFirst);
|
|
GL.glGetIntegerv(eGL_PACK_IMAGE_HEIGHT, &imageheight);
|
|
GL.glGetIntegerv(eGL_PACK_SKIP_IMAGES, &skipImages);
|
|
}
|
|
GL.glGetIntegerv(eGL_PACK_ROW_LENGTH, &rowlength);
|
|
GL.glGetIntegerv(eGL_PACK_SKIP_PIXELS, &skipPixels);
|
|
GL.glGetIntegerv(eGL_PACK_SKIP_ROWS, &skipRows);
|
|
GL.glGetIntegerv(eGL_PACK_ALIGNMENT, &alignment);
|
|
|
|
if(!IsGLES && compressed)
|
|
{
|
|
GL.glGetIntegerv(eGL_PACK_COMPRESSED_BLOCK_WIDTH, &compressedBlockWidth);
|
|
GL.glGetIntegerv(eGL_PACK_COMPRESSED_BLOCK_HEIGHT, &compressedBlockHeight);
|
|
GL.glGetIntegerv(eGL_PACK_COMPRESSED_BLOCK_DEPTH, &compressedBlockDepth);
|
|
GL.glGetIntegerv(eGL_PACK_COMPRESSED_BLOCK_SIZE, &compressedBlockSize);
|
|
}
|
|
}
|
|
|
|
void PixelPackState::Apply(bool compressed)
|
|
{
|
|
if(!IsGLES)
|
|
{
|
|
GL.glPixelStorei(eGL_PACK_SWAP_BYTES, swapBytes);
|
|
GL.glPixelStorei(eGL_PACK_LSB_FIRST, lsbFirst);
|
|
GL.glPixelStorei(eGL_PACK_IMAGE_HEIGHT, imageheight);
|
|
GL.glPixelStorei(eGL_PACK_SKIP_IMAGES, skipImages);
|
|
}
|
|
GL.glPixelStorei(eGL_PACK_ROW_LENGTH, rowlength);
|
|
GL.glPixelStorei(eGL_PACK_SKIP_PIXELS, skipPixels);
|
|
GL.glPixelStorei(eGL_PACK_SKIP_ROWS, skipRows);
|
|
GL.glPixelStorei(eGL_PACK_ALIGNMENT, alignment);
|
|
|
|
if(!IsGLES && compressed)
|
|
{
|
|
GL.glPixelStorei(eGL_PACK_COMPRESSED_BLOCK_WIDTH, compressedBlockWidth);
|
|
GL.glPixelStorei(eGL_PACK_COMPRESSED_BLOCK_HEIGHT, compressedBlockHeight);
|
|
GL.glPixelStorei(eGL_PACK_COMPRESSED_BLOCK_DEPTH, compressedBlockDepth);
|
|
GL.glPixelStorei(eGL_PACK_COMPRESSED_BLOCK_SIZE, compressedBlockSize);
|
|
}
|
|
}
|
|
|
|
void PixelUnpackState::Fetch(bool compressed)
|
|
{
|
|
if(!IsGLES)
|
|
{
|
|
GL.glGetIntegerv(eGL_UNPACK_SWAP_BYTES, &swapBytes);
|
|
GL.glGetIntegerv(eGL_UNPACK_LSB_FIRST, &lsbFirst);
|
|
}
|
|
GL.glGetIntegerv(eGL_UNPACK_ROW_LENGTH, &rowlength);
|
|
GL.glGetIntegerv(eGL_UNPACK_IMAGE_HEIGHT, &imageheight);
|
|
GL.glGetIntegerv(eGL_UNPACK_SKIP_PIXELS, &skipPixels);
|
|
GL.glGetIntegerv(eGL_UNPACK_SKIP_ROWS, &skipRows);
|
|
GL.glGetIntegerv(eGL_UNPACK_SKIP_IMAGES, &skipImages);
|
|
GL.glGetIntegerv(eGL_UNPACK_ALIGNMENT, &alignment);
|
|
|
|
if(!IsGLES && compressed)
|
|
{
|
|
GL.glGetIntegerv(eGL_UNPACK_COMPRESSED_BLOCK_WIDTH, &compressedBlockWidth);
|
|
GL.glGetIntegerv(eGL_UNPACK_COMPRESSED_BLOCK_HEIGHT, &compressedBlockHeight);
|
|
GL.glGetIntegerv(eGL_UNPACK_COMPRESSED_BLOCK_DEPTH, &compressedBlockDepth);
|
|
GL.glGetIntegerv(eGL_UNPACK_COMPRESSED_BLOCK_SIZE, &compressedBlockSize);
|
|
}
|
|
}
|
|
|
|
void PixelUnpackState::Apply(bool compressed)
|
|
{
|
|
if(!IsGLES)
|
|
{
|
|
GL.glPixelStorei(eGL_UNPACK_SWAP_BYTES, swapBytes);
|
|
GL.glPixelStorei(eGL_UNPACK_LSB_FIRST, lsbFirst);
|
|
}
|
|
GL.glPixelStorei(eGL_UNPACK_ROW_LENGTH, rowlength);
|
|
GL.glPixelStorei(eGL_UNPACK_IMAGE_HEIGHT, imageheight);
|
|
GL.glPixelStorei(eGL_UNPACK_SKIP_PIXELS, skipPixels);
|
|
GL.glPixelStorei(eGL_UNPACK_SKIP_ROWS, skipRows);
|
|
GL.glPixelStorei(eGL_UNPACK_SKIP_IMAGES, skipImages);
|
|
GL.glPixelStorei(eGL_UNPACK_ALIGNMENT, alignment);
|
|
|
|
if(!IsGLES && compressed)
|
|
{
|
|
GL.glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_WIDTH, compressedBlockWidth);
|
|
GL.glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_HEIGHT, compressedBlockHeight);
|
|
GL.glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_DEPTH, compressedBlockDepth);
|
|
GL.glPixelStorei(eGL_UNPACK_COMPRESSED_BLOCK_SIZE, compressedBlockSize);
|
|
}
|
|
}
|
|
|
|
bool PixelUnpackState::FastPath(GLsizei width, GLsizei height, GLsizei depth, GLenum dataformat,
|
|
GLenum basetype)
|
|
{
|
|
if(swapBytes)
|
|
return false;
|
|
|
|
if(skipPixels)
|
|
return false;
|
|
|
|
if(height > 0 && skipRows)
|
|
return false;
|
|
|
|
if(depth > 0 && skipImages)
|
|
return false;
|
|
|
|
if(width > 0 && rowlength > 0 && width < rowlength)
|
|
return false;
|
|
|
|
if(height > 0 && imageheight > 0 && height < imageheight)
|
|
return false;
|
|
|
|
if(alignment > (int32_t)GetByteSize(1, 1, 1, dataformat, basetype))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool PixelUnpackState::FastPathCompressed(GLsizei width, GLsizei height, GLsizei depth)
|
|
{
|
|
// compressedBlockSize and compressedBlockWidth must be set for any of the unpack params to be
|
|
// used
|
|
// if they are 0, all of the unpack params are ignored, so we go through the fast path (no
|
|
// unpacking)
|
|
if(compressedBlockSize == 0 || compressedBlockWidth == 0)
|
|
return true;
|
|
|
|
if(skipPixels)
|
|
return false;
|
|
|
|
if(width > 0 && rowlength > 0 && width < rowlength)
|
|
return false;
|
|
|
|
// the below two unpack params require compressedBlockHeight to be set so if we haven't "failed"
|
|
// to
|
|
// hit the fast path, none of the other params make a difference as they're ignored and we go
|
|
// through
|
|
// the fast path (no unpacking)
|
|
if(compressedBlockHeight == 0)
|
|
return true;
|
|
|
|
if(height > 0 && skipRows)
|
|
return false;
|
|
|
|
if(height > 0 && imageheight > 0 && height < imageheight)
|
|
return false;
|
|
|
|
// the final unpack param requires compressedBlockDepth to be set, as above if it's 0 then we can
|
|
// just go straight through the fast path (no unpacking)
|
|
if(compressedBlockDepth == 0)
|
|
return true;
|
|
|
|
if(depth > 0 && skipImages)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
byte *PixelUnpackState::Unpack(byte *pixels, GLsizei width, GLsizei height, GLsizei depth,
|
|
GLenum dataformat, GLenum basetype)
|
|
{
|
|
size_t pixelSize = GetByteSize(1, 1, 1, dataformat, basetype);
|
|
|
|
size_t srcrowstride = pixelSize * RDCMAX(RDCMAX(width, 1), rowlength);
|
|
size_t srcimgstride = srcrowstride * RDCMAX(RDCMAX(height, 1), imageheight);
|
|
|
|
size_t destrowstride = pixelSize * width;
|
|
size_t destimgstride = destrowstride * height;
|
|
|
|
size_t elemSize = GLTypeSize(basetype);
|
|
|
|
size_t allocsize = width * RDCMAX(1, height) * RDCMAX(1, depth) * pixelSize;
|
|
byte *ret = new byte[allocsize];
|
|
|
|
byte *source = pixels;
|
|
|
|
if(skipPixels > 0)
|
|
source += skipPixels * pixelSize;
|
|
if(skipRows > 0 && height > 0)
|
|
source += skipRows * srcrowstride;
|
|
if(skipImages > 0 && depth > 0)
|
|
source += skipImages * srcimgstride;
|
|
|
|
size_t align = 1;
|
|
// "If the number of bits per element is not 1, 2, 4, or 8 times the number of
|
|
// bits in a GL ubyte, then k = nl for all values of a"
|
|
// ie. alignment is only used for pixel formats with N-byte elements.
|
|
if(basetype == eGL_UNSIGNED_BYTE || basetype == eGL_BYTE || basetype == eGL_UNSIGNED_SHORT ||
|
|
basetype == eGL_SHORT || basetype == eGL_UNSIGNED_INT || basetype == eGL_INT ||
|
|
basetype == eGL_HALF_FLOAT || basetype == eGL_FLOAT || basetype == eGL_UNSIGNED_INT_8_8_8_8 ||
|
|
basetype == eGL_UNSIGNED_INT_8_8_8_8_REV)
|
|
{
|
|
align = RDCMAX(align, (size_t)alignment);
|
|
}
|
|
|
|
byte *dest = ret;
|
|
|
|
for(GLsizei img = 0; img < RDCMAX(1, depth); img++)
|
|
{
|
|
byte *rowsource = source;
|
|
byte *rowdest = dest;
|
|
|
|
for(GLsizei row = 0; row < RDCMAX(1, height); row++)
|
|
{
|
|
memcpy(rowdest, rowsource, destrowstride);
|
|
|
|
if(swapBytes && elemSize > 1)
|
|
{
|
|
for(size_t el = 0; el < pixelSize * width; el += elemSize)
|
|
{
|
|
byte *element = rowdest + el;
|
|
|
|
if(elemSize == 2)
|
|
{
|
|
std::swap(element[0], element[1]);
|
|
}
|
|
else if(elemSize == 4)
|
|
{
|
|
std::swap(element[0], element[3]);
|
|
std::swap(element[1], element[2]);
|
|
}
|
|
else if(elemSize == 8)
|
|
{
|
|
std::swap(element[0], element[7]);
|
|
std::swap(element[1], element[6]);
|
|
std::swap(element[2], element[5]);
|
|
std::swap(element[3], element[4]);
|
|
}
|
|
}
|
|
}
|
|
|
|
rowdest += destrowstride;
|
|
rowsource += srcrowstride;
|
|
rowsource = (byte *)AlignUp((size_t)rowsource, align);
|
|
}
|
|
|
|
dest += destimgstride;
|
|
source += srcimgstride;
|
|
source = (byte *)AlignUp((size_t)source, align);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
byte *PixelUnpackState::UnpackCompressed(byte *pixels, GLsizei width, GLsizei height, GLsizei depth,
|
|
GLsizei &imageSize)
|
|
{
|
|
int blockWidth = RDCMAX(compressedBlockWidth, 1);
|
|
int blockHeight = RDCMAX(compressedBlockHeight, 1);
|
|
int blockDepth = RDCMAX(compressedBlockDepth, 1);
|
|
int blockSize = RDCMAX(compressedBlockSize, 1);
|
|
|
|
RDCASSERT(compressedBlockWidth != 0);
|
|
RDCASSERT(compressedBlockSize != 0);
|
|
|
|
size_t blocksX = width ? (width + blockWidth - 1) / blockWidth : 0;
|
|
size_t blocksY = height ? (height + blockHeight - 1) / blockHeight : 0;
|
|
size_t blocksZ = depth ? (depth + blockDepth - 1) / blockDepth : 0;
|
|
|
|
if(height != 0)
|
|
RDCASSERT(compressedBlockHeight != 0);
|
|
|
|
if(depth != 0)
|
|
RDCASSERT(compressedBlockDepth != 0);
|
|
|
|
blocksX = RDCMAX((size_t)1, blocksX);
|
|
blocksY = RDCMAX((size_t)1, blocksY);
|
|
blocksZ = RDCMAX((size_t)1, blocksZ);
|
|
|
|
size_t srcrowstride = blockSize * RDCMAX(RDCMAX(width, blockWidth), rowlength) / blockWidth;
|
|
size_t srcimgstride = srcrowstride * RDCMAX(RDCMAX(height, blockHeight), imageheight) / blockHeight;
|
|
|
|
size_t destrowstride = blockSize * RDCMAX(width, blockWidth) / blockWidth;
|
|
size_t destimgstride = destrowstride * RDCMAX(height, blockHeight) / blockHeight;
|
|
|
|
size_t allocsize = blocksX * blocksY * blocksZ * blockSize;
|
|
byte *ret = new byte[allocsize];
|
|
|
|
imageSize = (GLsizei)allocsize;
|
|
|
|
byte *source = pixels;
|
|
|
|
if(skipPixels > 0)
|
|
source += (skipPixels / blockWidth) * blockSize;
|
|
if(skipRows > 0 && height > 0)
|
|
source += (skipRows / compressedBlockHeight) * srcrowstride;
|
|
if(skipImages > 0 && depth > 0)
|
|
source += skipImages * srcimgstride;
|
|
|
|
byte *dest = ret;
|
|
|
|
for(GLsizei img = 0; img < RDCMAX(1, depth); img++)
|
|
{
|
|
byte *rowsource = source;
|
|
byte *rowdest = dest;
|
|
|
|
for(size_t row = 0; row < blocksY; row++)
|
|
{
|
|
memcpy(rowdest, rowsource, destrowstride);
|
|
|
|
rowsource += srcrowstride;
|
|
rowdest += destrowstride;
|
|
}
|
|
|
|
source += srcimgstride;
|
|
dest += destimgstride;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
GLRenderState::GLRenderState()
|
|
{
|
|
Clear();
|
|
|
|
for(GLuint i = 0; i < (GLuint)ARRAY_COUNT(Tex2D); i++)
|
|
{
|
|
Tex1D[i].Namespace = Tex2D[i].Namespace = Tex3D[i].Namespace = Tex1DArray[i].Namespace =
|
|
Tex2DArray[i].Namespace = TexCubeArray[i].Namespace = TexRect[i].Namespace =
|
|
TexBuffer[i].Namespace = TexCube[i].Namespace = Tex2DMS[i].Namespace =
|
|
Tex2DMSArray[i].Namespace = eResTexture;
|
|
Samplers[i].Namespace = eResSampler;
|
|
}
|
|
|
|
Program.Namespace = eResProgram;
|
|
Pipeline.Namespace = eResProgramPipe;
|
|
VAO.Namespace = eResVertexArray;
|
|
|
|
FeedbackObj.Namespace = eResFeedback;
|
|
|
|
for(GLuint i = 0; i < (GLuint)ARRAY_COUNT(BufferBindings); i++)
|
|
BufferBindings[i].Namespace = eResBuffer;
|
|
|
|
for(GLuint i = 0; i < (GLuint)ARRAY_COUNT(AtomicCounter); i++)
|
|
AtomicCounter[i].res.Namespace = eResBuffer;
|
|
for(GLuint i = 0; i < (GLuint)ARRAY_COUNT(ShaderStorage); i++)
|
|
ShaderStorage[i].res.Namespace = eResBuffer;
|
|
for(GLuint i = 0; i < (GLuint)ARRAY_COUNT(TransformFeedback); i++)
|
|
TransformFeedback[i].res.Namespace = eResBuffer;
|
|
for(GLuint i = 0; i < (GLuint)ARRAY_COUNT(UniformBinding); i++)
|
|
UniformBinding[i].res.Namespace = eResBuffer;
|
|
for(GLuint i = 0; i < (GLuint)ARRAY_COUNT(Images); i++)
|
|
Images[i].res.Namespace = eResTexture;
|
|
|
|
ReadFBO.Namespace = DrawFBO.Namespace = eResFramebuffer;
|
|
}
|
|
|
|
GLRenderState::~GLRenderState()
|
|
{
|
|
}
|
|
|
|
void GLRenderState::MarkReferenced(WrappedOpenGL *driver, bool initial) const
|
|
{
|
|
GLResourceManager *manager = driver->GetResourceManager();
|
|
|
|
for(GLuint i = 0; i < (GLuint)ARRAY_COUNT(Tex2D); i++)
|
|
{
|
|
manager->MarkResourceFrameReferenced(Tex1D[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(Tex2D[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(Tex3D[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(Tex1DArray[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(Tex2DArray[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(TexCubeArray[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(TexRect[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(TexBuffer[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(TexCube[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(Tex2DMS[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(Tex2DMSArray[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(Samplers[i], initial ? eFrameRef_None : eFrameRef_Read);
|
|
}
|
|
|
|
for(GLuint i = 0; i < (GLuint)ARRAY_COUNT(Images); i++)
|
|
{
|
|
manager->MarkResourceFrameReferenced(Images[i].res,
|
|
initial ? eFrameRef_None : eFrameRef_ReadBeforeWrite);
|
|
}
|
|
|
|
manager->MarkVAOReferenced(VAO, initial ? eFrameRef_None : eFrameRef_Read, true);
|
|
|
|
manager->MarkResourceFrameReferenced(FeedbackObj, initial ? eFrameRef_None : eFrameRef_Read);
|
|
|
|
manager->MarkResourceFrameReferenced(Program, initial ? eFrameRef_None : eFrameRef_Read);
|
|
manager->MarkResourceFrameReferenced(Pipeline, initial ? eFrameRef_None : eFrameRef_Read);
|
|
|
|
{
|
|
// mark all the sub programs referenced
|
|
GLenum programBinds[] = {
|
|
eGL_VERTEX_SHADER, eGL_FRAGMENT_SHADER, eGL_GEOMETRY_SHADER,
|
|
eGL_TESS_CONTROL_SHADER, eGL_TESS_EVALUATION_SHADER, eGL_COMPUTE_SHADER,
|
|
};
|
|
|
|
for(GLenum progbind : programBinds)
|
|
{
|
|
GLuint prog = 0;
|
|
GL.glGetProgramPipelineiv(Pipeline.name, progbind, (GLint *)&prog);
|
|
if(prog)
|
|
manager->MarkResourceFrameReferenced(ProgramRes(driver->GetCtx(), prog),
|
|
initial ? eFrameRef_None : eFrameRef_Read);
|
|
}
|
|
}
|
|
|
|
for(size_t i = 0; i < ARRAY_COUNT(BufferBindings); i++)
|
|
manager->MarkResourceFrameReferenced(BufferBindings[i],
|
|
initial ? eFrameRef_None : eFrameRef_Read);
|
|
|
|
for(size_t i = 0; i < ARRAY_COUNT(AtomicCounter); i++)
|
|
manager->MarkResourceFrameReferenced(AtomicCounter[i].res,
|
|
initial ? eFrameRef_None : eFrameRef_ReadBeforeWrite);
|
|
|
|
for(size_t i = 0; i < ARRAY_COUNT(ShaderStorage); i++)
|
|
manager->MarkResourceFrameReferenced(ShaderStorage[i].res,
|
|
initial ? eFrameRef_None : eFrameRef_ReadBeforeWrite);
|
|
|
|
for(size_t i = 0; i < ARRAY_COUNT(TransformFeedback); i++)
|
|
manager->MarkResourceFrameReferenced(TransformFeedback[i].res,
|
|
initial ? eFrameRef_None : eFrameRef_ReadBeforeWrite);
|
|
|
|
for(size_t i = 0; i < ARRAY_COUNT(UniformBinding); i++)
|
|
manager->MarkResourceFrameReferenced(UniformBinding[i].res,
|
|
initial ? eFrameRef_None : eFrameRef_Read);
|
|
|
|
manager->MarkFBOReferenced(DrawFBO, initial ? eFrameRef_None : eFrameRef_ReadBeforeWrite);
|
|
|
|
// if same FBO is bound to both targets, treat it as draw only
|
|
if(ReadFBO != DrawFBO)
|
|
manager->MarkFBOReferenced(ReadFBO, initial ? eFrameRef_None : eFrameRef_Read);
|
|
|
|
MarkDirty(driver);
|
|
}
|
|
|
|
void GLRenderState::MarkDirty(WrappedOpenGL *driver) const
|
|
{
|
|
GLResourceManager *manager = driver->GetResourceManager();
|
|
|
|
ContextPair &ctx = driver->GetCtx();
|
|
|
|
GLint maxCount = 0;
|
|
GLuint name = 0;
|
|
|
|
if(HasExt[ARB_transform_feedback2])
|
|
{
|
|
GL.glGetIntegerv(eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &maxCount);
|
|
|
|
for(GLint i = 0; i < maxCount; i++)
|
|
{
|
|
name = 0;
|
|
GL.glGetIntegeri_v(eGL_TRANSFORM_FEEDBACK_BUFFER_BINDING, i, (GLint *)&name);
|
|
|
|
if(name)
|
|
manager->MarkDirtyWithWriteReference(BufferRes(ctx, name));
|
|
}
|
|
}
|
|
|
|
if(HasExt[ARB_shader_image_load_store])
|
|
{
|
|
GL.glGetIntegerv(eGL_MAX_IMAGE_UNITS, &maxCount);
|
|
|
|
for(GLint i = 0; i < maxCount; i++)
|
|
{
|
|
name = 0;
|
|
GL.glGetIntegeri_v(eGL_IMAGE_BINDING_NAME, i, (GLint *)&name);
|
|
|
|
if(name)
|
|
manager->MarkDirtyWithWriteReference(TextureRes(ctx, name));
|
|
}
|
|
}
|
|
|
|
if(HasExt[ARB_shader_atomic_counters])
|
|
{
|
|
GL.glGetIntegerv(eGL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &maxCount);
|
|
|
|
for(GLint i = 0; i < maxCount; i++)
|
|
{
|
|
name = 0;
|
|
GL.glGetIntegeri_v(eGL_ATOMIC_COUNTER_BUFFER_BINDING, i, (GLint *)&name);
|
|
|
|
if(name)
|
|
manager->MarkDirtyWithWriteReference(BufferRes(ctx, name));
|
|
}
|
|
}
|
|
|
|
if(HasExt[ARB_shader_storage_buffer_object])
|
|
{
|
|
GL.glGetIntegerv(eGL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &maxCount);
|
|
|
|
for(GLint i = 0; i < maxCount; i++)
|
|
{
|
|
name = 0;
|
|
GL.glGetIntegeri_v(eGL_SHADER_STORAGE_BUFFER_BINDING, i, (GLint *)&name);
|
|
|
|
if(name)
|
|
manager->MarkDirtyWithWriteReference(BufferRes(ctx, name));
|
|
}
|
|
}
|
|
|
|
GL.glGetIntegerv(eGL_MAX_COLOR_ATTACHMENTS, &maxCount);
|
|
|
|
GL.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&name);
|
|
|
|
if(name)
|
|
{
|
|
GLenum type = eGL_TEXTURE;
|
|
for(GLint i = 0; i < maxCount; i++)
|
|
{
|
|
GL.glGetFramebufferAttachmentParameteriv(
|
|
eGL_DRAW_FRAMEBUFFER, GLenum(eGL_COLOR_ATTACHMENT0 + i),
|
|
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint *)&name);
|
|
GL.glGetFramebufferAttachmentParameteriv(
|
|
eGL_DRAW_FRAMEBUFFER, GLenum(eGL_COLOR_ATTACHMENT0 + i),
|
|
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, (GLint *)&type);
|
|
|
|
if(name)
|
|
{
|
|
if(type == eGL_RENDERBUFFER)
|
|
manager->MarkDirtyResource(RenderbufferRes(ctx, name));
|
|
else
|
|
manager->MarkDirtyWithWriteReference(TextureRes(ctx, name));
|
|
}
|
|
}
|
|
|
|
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT,
|
|
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint *)&name);
|
|
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT,
|
|
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, (GLint *)&type);
|
|
|
|
if(name)
|
|
{
|
|
if(type == eGL_RENDERBUFFER)
|
|
manager->MarkDirtyResource(RenderbufferRes(ctx, name));
|
|
else
|
|
manager->MarkDirtyWithWriteReference(TextureRes(ctx, name));
|
|
}
|
|
|
|
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT,
|
|
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint *)&name);
|
|
GL.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT,
|
|
eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, (GLint *)&type);
|
|
|
|
if(name)
|
|
{
|
|
if(type == eGL_RENDERBUFFER)
|
|
manager->MarkDirtyResource(RenderbufferRes(ctx, name));
|
|
else
|
|
manager->MarkDirtyWithWriteReference(TextureRes(ctx, name));
|
|
}
|
|
}
|
|
}
|
|
|
|
bool GLRenderState::CheckEnableDisableParam(GLenum pname)
|
|
{
|
|
RDCCOMPILE_ASSERT(ARRAY_COUNT(enable_disable_cap) == eEnabled_Count,
|
|
"Wrong number of capabilities");
|
|
|
|
if(IsGLES)
|
|
{
|
|
switch(pname)
|
|
{
|
|
case eGL_COLOR_LOGIC_OP:
|
|
case eGL_DEPTH_CLAMP:
|
|
case eGL_DEPTH_BOUNDS_TEST_EXT:
|
|
case eGL_LINE_SMOOTH:
|
|
case eGL_POLYGON_SMOOTH:
|
|
case eGL_PROGRAM_POINT_SIZE:
|
|
case eGL_PRIMITIVE_RESTART:
|
|
case eGL_TEXTURE_CUBE_MAP_SEAMLESS:
|
|
// these are not supported by OpenGL ES
|
|
return false;
|
|
|
|
case eGL_POLYGON_OFFSET_LINE:
|
|
case eGL_POLYGON_OFFSET_POINT:
|
|
// these are in GL_NV_polygon_mode, however they are not accepted by the NVIDIA driver
|
|
// see DoVendorChecks()
|
|
return false;
|
|
|
|
case eGL_SAMPLE_MASK:
|
|
return HasExt[ARB_texture_multisample_no_array] || HasExt[ARB_texture_multisample];
|
|
|
|
case eGL_CLIP_DISTANCE0:
|
|
case eGL_CLIP_DISTANCE1:
|
|
case eGL_CLIP_DISTANCE2:
|
|
case eGL_CLIP_DISTANCE3:
|
|
case eGL_CLIP_DISTANCE4:
|
|
case eGL_CLIP_DISTANCE5:
|
|
case eGL_CLIP_DISTANCE6:
|
|
case eGL_CLIP_DISTANCE7: return HasExt[EXT_clip_cull_distance];
|
|
|
|
case eGL_SAMPLE_ALPHA_TO_ONE:
|
|
case eGL_MULTISAMPLE: return HasExt[EXT_multisample_compatibility];
|
|
|
|
case eGL_SAMPLE_SHADING: return HasExt[ARB_sample_shading];
|
|
|
|
case eGL_FRAMEBUFFER_SRGB: return HasExt[EXT_framebuffer_sRGB];
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch(pname)
|
|
{
|
|
case eGL_DEPTH_BOUNDS_TEST_EXT: return HasExt[EXT_depth_bounds_test];
|
|
case eGL_SAMPLE_SHADING: return HasExt[ARB_sample_shading];
|
|
case eGL_PRIMITIVE_RESTART_FIXED_INDEX: return HasExt[ARB_ES3_compatibility];
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
// both OpenGL and OpenGL ES
|
|
switch(pname)
|
|
{
|
|
case eGL_BLEND_ADVANCED_COHERENT_KHR: return HasExt[KHR_blend_equation_advanced_coherent];
|
|
case eGL_RASTER_MULTISAMPLE_EXT: return HasExt[EXT_raster_multisample];
|
|
case eGL_RASTERIZER_DISCARD: return HasExt[EXT_transform_feedback];
|
|
default: break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void GLRenderState::FetchState(WrappedOpenGL *driver)
|
|
{
|
|
ContextPair &ctx = driver->GetCtx();
|
|
|
|
if(ctx.ctx == NULL)
|
|
{
|
|
ContextPresent = false;
|
|
return;
|
|
}
|
|
|
|
for(GLuint i = 0; i < eEnabled_Count; i++)
|
|
{
|
|
if(!CheckEnableDisableParam(enable_disable_cap[i].cap))
|
|
{
|
|
Enabled[i] = false;
|
|
continue;
|
|
}
|
|
|
|
Enabled[i] = (GL.glIsEnabled(enable_disable_cap[i].cap) == GL_TRUE);
|
|
}
|
|
|
|
GL.glGetIntegerv(eGL_ACTIVE_TEXTURE, (GLint *)&ActiveTexture);
|
|
|
|
GLuint maxTextures = 0;
|
|
GL.glGetIntegerv(eGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, (GLint *)&maxTextures);
|
|
|
|
RDCCOMPILE_ASSERT(
|
|
sizeof(Tex1D) == sizeof(Tex2D) && sizeof(Tex2D) == sizeof(Tex3D) &&
|
|
sizeof(Tex3D) == sizeof(Tex1DArray) && sizeof(Tex1DArray) == sizeof(Tex2DArray) &&
|
|
sizeof(Tex2DArray) == sizeof(TexCubeArray) && sizeof(TexCubeArray) == sizeof(TexRect) &&
|
|
sizeof(TexRect) == sizeof(TexBuffer) && sizeof(TexBuffer) == sizeof(TexCube) &&
|
|
sizeof(TexCube) == sizeof(Tex2DMS) && sizeof(Tex2DMS) == sizeof(Tex2DMSArray) &&
|
|
sizeof(Tex2DMSArray) == sizeof(Samplers),
|
|
"All texture arrays should be identically sized");
|
|
|
|
for(GLuint i = 0; i < RDCMIN(maxTextures, (GLuint)ARRAY_COUNT(Tex2D)); i++)
|
|
{
|
|
GL.glActiveTexture(GLenum(eGL_TEXTURE0 + i));
|
|
|
|
// textures are always shared
|
|
Tex1D[i].ContextShareGroup = ctx.shareGroup;
|
|
Tex2D[i].ContextShareGroup = ctx.shareGroup;
|
|
Tex3D[i].ContextShareGroup = ctx.shareGroup;
|
|
Tex1DArray[i].ContextShareGroup = ctx.shareGroup;
|
|
Tex2DArray[i].ContextShareGroup = ctx.shareGroup;
|
|
TexCube[i].ContextShareGroup = ctx.shareGroup;
|
|
TexRect[i].ContextShareGroup = ctx.shareGroup;
|
|
TexBuffer[i].ContextShareGroup = ctx.shareGroup;
|
|
Tex2DMS[i].ContextShareGroup = ctx.shareGroup;
|
|
Tex2DMSArray[i].ContextShareGroup = ctx.shareGroup;
|
|
TexCubeArray[i].ContextShareGroup = ctx.shareGroup;
|
|
Samplers[i].ContextShareGroup = ctx.shareGroup;
|
|
|
|
if(!IsGLES)
|
|
GL.glGetIntegerv(eGL_TEXTURE_BINDING_1D, (GLint *)&Tex1D[i].name);
|
|
else
|
|
Tex1D[i].name = 0;
|
|
|
|
GL.glGetIntegerv(eGL_TEXTURE_BINDING_2D, (GLint *)&Tex2D[i].name);
|
|
GL.glGetIntegerv(eGL_TEXTURE_BINDING_3D, (GLint *)&Tex3D[i].name);
|
|
|
|
if(!IsGLES)
|
|
GL.glGetIntegerv(eGL_TEXTURE_BINDING_1D_ARRAY, (GLint *)&Tex1DArray[i].name);
|
|
else
|
|
Tex1DArray[i].name = 0;
|
|
|
|
GL.glGetIntegerv(eGL_TEXTURE_BINDING_2D_ARRAY, (GLint *)&Tex2DArray[i].name);
|
|
GL.glGetIntegerv(eGL_TEXTURE_BINDING_CUBE_MAP, (GLint *)&TexCube[i].name);
|
|
|
|
if(!IsGLES)
|
|
GL.glGetIntegerv(eGL_TEXTURE_BINDING_RECTANGLE, (GLint *)&TexRect[i].name);
|
|
else
|
|
TexRect[i].name = 0;
|
|
|
|
if(HasExt[ARB_texture_buffer_object])
|
|
GL.glGetIntegerv(eGL_TEXTURE_BINDING_BUFFER, (GLint *)&TexBuffer[i].name);
|
|
else
|
|
TexBuffer[i].name = 0;
|
|
|
|
if(HasExt[ARB_texture_multisample_no_array] || HasExt[ARB_texture_multisample])
|
|
GL.glGetIntegerv(eGL_TEXTURE_BINDING_2D_MULTISAMPLE, (GLint *)&Tex2DMS[i].name);
|
|
else
|
|
Tex2DMS[i].name = 0;
|
|
|
|
if(HasExt[ARB_texture_multisample])
|
|
GL.glGetIntegerv(eGL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY, (GLint *)&Tex2DMSArray[i].name);
|
|
else
|
|
Tex2DMSArray[i].name = 0;
|
|
|
|
if(HasExt[ARB_texture_cube_map_array])
|
|
GL.glGetIntegerv(eGL_TEXTURE_BINDING_CUBE_MAP_ARRAY, (GLint *)&TexCubeArray[i].name);
|
|
else
|
|
TexCubeArray[i].name = 0;
|
|
|
|
if(HasExt[ARB_sampler_objects])
|
|
GL.glGetIntegerv(eGL_SAMPLER_BINDING, (GLint *)&Samplers[i].name);
|
|
else
|
|
Samplers[i].name = 0;
|
|
}
|
|
|
|
if(HasExt[ARB_shader_image_load_store])
|
|
{
|
|
GLuint maxImages = 0;
|
|
GL.glGetIntegerv(eGL_MAX_IMAGE_UNITS, (GLint *)&maxImages);
|
|
|
|
for(GLuint i = 0; i < RDCMIN(maxImages, (GLuint)ARRAY_COUNT(Images)); i++)
|
|
{
|
|
GLboolean layered = GL_FALSE;
|
|
|
|
// textures are always shared
|
|
Images[i].res.ContextShareGroup = ctx.shareGroup;
|
|
|
|
GL.glGetIntegeri_v(eGL_IMAGE_BINDING_NAME, i, (GLint *)&Images[i].res.name);
|
|
GL.glGetIntegeri_v(eGL_IMAGE_BINDING_LEVEL, i, (GLint *)&Images[i].level);
|
|
GL.glGetIntegeri_v(eGL_IMAGE_BINDING_ACCESS, i, (GLint *)&Images[i].access);
|
|
GL.glGetIntegeri_v(eGL_IMAGE_BINDING_FORMAT, i, (GLint *)&Images[i].format);
|
|
GL.glGetBooleani_v(eGL_IMAGE_BINDING_LAYERED, i, &layered);
|
|
Images[i].layered = (layered == GL_TRUE);
|
|
if(layered)
|
|
GL.glGetIntegeri_v(eGL_IMAGE_BINDING_LAYER, i, (GLint *)&Images[i].layer);
|
|
}
|
|
}
|
|
|
|
GL.glActiveTexture(ActiveTexture);
|
|
|
|
{
|
|
GLuint name = 0;
|
|
GL.glGetIntegerv(eGL_VERTEX_ARRAY_BINDING, (GLint *)&name);
|
|
VAO = VertexArrayRes(ctx, name);
|
|
}
|
|
|
|
if(HasExt[ARB_transform_feedback2])
|
|
{
|
|
GLuint name = 0;
|
|
GL.glGetIntegerv(eGL_TRANSFORM_FEEDBACK_BINDING, (GLint *)&name);
|
|
FeedbackObj = FeedbackRes(ctx, name);
|
|
}
|
|
|
|
// the spec says that you can only query for the format that was previously set, or you get
|
|
// undefined results. Ie. if someone set ints, this might return anything. However there's also
|
|
// no way to query for the type so we just have to hope for the best and hope most people are
|
|
// sane and don't use these except for a default "all 0s" attrib.
|
|
|
|
GLuint maxNumAttribs = 0;
|
|
GL.glGetIntegerv(eGL_MAX_VERTEX_ATTRIBS, (GLint *)&maxNumAttribs);
|
|
for(GLuint i = 0; i < RDCMIN(maxNumAttribs, (GLuint)ARRAY_COUNT(GenericVertexAttribs)); i++)
|
|
GL.glGetVertexAttribfv(i, eGL_CURRENT_VERTEX_ATTRIB, &GenericVertexAttribs[i].x);
|
|
|
|
GL.glGetFloatv(eGL_LINE_WIDTH, &LineWidth);
|
|
if(!IsGLES)
|
|
{
|
|
GL.glGetFloatv(eGL_POINT_FADE_THRESHOLD_SIZE, &PointFadeThresholdSize);
|
|
GL.glGetIntegerv(eGL_POINT_SPRITE_COORD_ORIGIN, (GLint *)&PointSpriteOrigin);
|
|
GL.glGetFloatv(eGL_POINT_SIZE, &PointSize);
|
|
}
|
|
|
|
if(!IsGLES)
|
|
GL.glGetIntegerv(eGL_PRIMITIVE_RESTART_INDEX, (GLint *)&PrimitiveRestartIndex);
|
|
if(HasExt[ARB_clip_control])
|
|
{
|
|
GL.glGetIntegerv(eGL_CLIP_ORIGIN, (GLint *)&ClipOrigin);
|
|
GL.glGetIntegerv(eGL_CLIP_DEPTH_MODE, (GLint *)&ClipDepth);
|
|
}
|
|
else
|
|
{
|
|
ClipOrigin = eGL_LOWER_LEFT;
|
|
ClipDepth = eGL_NEGATIVE_ONE_TO_ONE;
|
|
}
|
|
if(!IsGLES)
|
|
GL.glGetIntegerv(eGL_PROVOKING_VERTEX, (GLint *)&ProvokingVertex);
|
|
|
|
{
|
|
GLuint name = 0;
|
|
GL.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint *)&name);
|
|
Program = ProgramRes(ctx, name);
|
|
}
|
|
|
|
if(HasExt[ARB_separate_shader_objects])
|
|
{
|
|
GLuint name = 0;
|
|
GL.glGetIntegerv(eGL_PROGRAM_PIPELINE_BINDING, (GLint *)&name);
|
|
Pipeline = ProgramPipeRes(ctx, name);
|
|
}
|
|
else
|
|
{
|
|
Pipeline = ProgramRes(ctx, 0);
|
|
}
|
|
|
|
const GLenum shs[] = {
|
|
eGL_VERTEX_SHADER, eGL_TESS_CONTROL_SHADER, eGL_TESS_EVALUATION_SHADER,
|
|
eGL_GEOMETRY_SHADER, eGL_FRAGMENT_SHADER, eGL_COMPUTE_SHADER,
|
|
};
|
|
|
|
if(HasExt[ARB_shader_subroutine])
|
|
{
|
|
RDCCOMPILE_ASSERT(ARRAY_COUNT(shs) == ARRAY_COUNT(Subroutines),
|
|
"Subroutine array not the right size");
|
|
|
|
for(size_t s = 0; s < ARRAY_COUNT(shs); s++)
|
|
{
|
|
if(shs[s] == eGL_COMPUTE_SHADER && !HasExt[ARB_compute_shader])
|
|
continue;
|
|
|
|
if((shs[s] == eGL_TESS_CONTROL_SHADER || shs[s] == eGL_TESS_EVALUATION_SHADER) &&
|
|
!HasExt[ARB_tessellation_shader])
|
|
continue;
|
|
|
|
GLuint prog = Program.name;
|
|
if(prog == 0 && Pipeline.name != 0)
|
|
{
|
|
// can't query for GL_COMPUTE_SHADER on some AMD cards
|
|
if(shs[s] != eGL_COMPUTE_SHADER || !VendorCheck[VendorCheck_AMD_pipeline_compute_query])
|
|
GL.glGetProgramPipelineiv(Pipeline.name, shs[s], (GLint *)&prog);
|
|
}
|
|
|
|
if(prog == 0)
|
|
continue;
|
|
|
|
GLint numSubroutines = 0;
|
|
GL.glGetProgramStageiv(prog, shs[s], eGL_ACTIVE_SUBROUTINES, &numSubroutines);
|
|
|
|
if(numSubroutines == 0)
|
|
continue;
|
|
|
|
GL.glGetProgramStageiv(prog, shs[s], eGL_ACTIVE_SUBROUTINE_UNIFORM_LOCATIONS,
|
|
&Subroutines[s].numSubroutines);
|
|
|
|
for(GLint i = 0; i < Subroutines[s].numSubroutines; i++)
|
|
GL.glGetUniformSubroutineuiv(shs[s], i, &Subroutines[s].Values[0]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RDCEraseEl(Subroutines);
|
|
}
|
|
|
|
// buffers are always shared
|
|
for(size_t i = 0; i < ARRAY_COUNT(BufferBindings); i++)
|
|
BufferBindings[i].ContextShareGroup = ctx.shareGroup;
|
|
|
|
GL.glGetIntegerv(eGL_ARRAY_BUFFER_BINDING, (GLint *)&BufferBindings[eBufIdx_Array].name);
|
|
GL.glGetIntegerv(eGL_COPY_READ_BUFFER_BINDING, (GLint *)&BufferBindings[eBufIdx_Copy_Read].name);
|
|
GL.glGetIntegerv(eGL_COPY_WRITE_BUFFER_BINDING, (GLint *)&BufferBindings[eBufIdx_Copy_Write].name);
|
|
GL.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint *)&BufferBindings[eBufIdx_Pixel_Pack].name);
|
|
GL.glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING,
|
|
(GLint *)&BufferBindings[eBufIdx_Pixel_Unpack].name);
|
|
if(HasExt[ARB_texture_buffer_object])
|
|
GL.glGetIntegerv(eGL_TEXTURE_BUFFER_BINDING, (GLint *)&BufferBindings[eBufIdx_Texture].name);
|
|
|
|
if(HasExt[ARB_draw_indirect])
|
|
GL.glGetIntegerv(eGL_DRAW_INDIRECT_BUFFER_BINDING,
|
|
(GLint *)&BufferBindings[eBufIdx_Draw_Indirect].name);
|
|
if(HasExt[ARB_compute_shader])
|
|
GL.glGetIntegerv(eGL_DISPATCH_INDIRECT_BUFFER_BINDING,
|
|
(GLint *)&BufferBindings[eBufIdx_Dispatch_Indirect].name);
|
|
if(HasExt[ARB_query_buffer_object])
|
|
GL.glGetIntegerv(eGL_QUERY_BUFFER_BINDING, (GLint *)&BufferBindings[eBufIdx_Query].name);
|
|
if(HasExt[ARB_indirect_parameters])
|
|
GL.glGetIntegerv(eGL_PARAMETER_BUFFER_BINDING_ARB,
|
|
(GLint *)&BufferBindings[eBufIdx_Parameter].name);
|
|
|
|
struct
|
|
{
|
|
IdxRangeBuffer *bufs;
|
|
int count;
|
|
GLenum binding;
|
|
GLenum start;
|
|
GLenum size;
|
|
GLenum maxcount;
|
|
} idxBufs[] = {
|
|
{
|
|
AtomicCounter, ARRAY_COUNT(AtomicCounter), eGL_ATOMIC_COUNTER_BUFFER_BINDING,
|
|
eGL_ATOMIC_COUNTER_BUFFER_START, eGL_ATOMIC_COUNTER_BUFFER_SIZE,
|
|
eGL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,
|
|
},
|
|
{
|
|
ShaderStorage, ARRAY_COUNT(ShaderStorage), eGL_SHADER_STORAGE_BUFFER_BINDING,
|
|
eGL_SHADER_STORAGE_BUFFER_START, eGL_SHADER_STORAGE_BUFFER_SIZE,
|
|
eGL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,
|
|
},
|
|
{
|
|
TransformFeedback, ARRAY_COUNT(TransformFeedback), eGL_TRANSFORM_FEEDBACK_BUFFER_BINDING,
|
|
eGL_TRANSFORM_FEEDBACK_BUFFER_START, eGL_TRANSFORM_FEEDBACK_BUFFER_SIZE,
|
|
eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
|
|
},
|
|
{
|
|
UniformBinding, ARRAY_COUNT(UniformBinding), eGL_UNIFORM_BUFFER_BINDING,
|
|
eGL_UNIFORM_BUFFER_START, eGL_UNIFORM_BUFFER_SIZE, eGL_MAX_UNIFORM_BUFFER_BINDINGS,
|
|
},
|
|
};
|
|
|
|
for(GLuint b = 0; b < (GLuint)ARRAY_COUNT(idxBufs); b++)
|
|
{
|
|
if(idxBufs[b].binding == eGL_ATOMIC_COUNTER_BUFFER_BINDING && !HasExt[ARB_shader_atomic_counters])
|
|
continue;
|
|
|
|
if(idxBufs[b].binding == eGL_SHADER_STORAGE_BUFFER_BINDING &&
|
|
!HasExt[ARB_shader_storage_buffer_object])
|
|
continue;
|
|
|
|
if(idxBufs[b].binding == eGL_TRANSFORM_FEEDBACK_BUFFER_BINDING && !HasExt[ARB_transform_feedback2])
|
|
continue;
|
|
|
|
GLint maxCount = 0;
|
|
GL.glGetIntegerv(idxBufs[b].maxcount, &maxCount);
|
|
for(int i = 0; i < idxBufs[b].count && i < maxCount; i++)
|
|
{
|
|
// buffers are always shared
|
|
idxBufs[b].bufs[i].res.ContextShareGroup = ctx.shareGroup;
|
|
|
|
GL.glGetIntegeri_v(idxBufs[b].binding, i, (GLint *)&idxBufs[b].bufs[i].res.name);
|
|
GL.glGetInteger64i_v(idxBufs[b].start, i, (GLint64 *)&idxBufs[b].bufs[i].start);
|
|
GL.glGetInteger64i_v(idxBufs[b].size, i, (GLint64 *)&idxBufs[b].bufs[i].size);
|
|
}
|
|
}
|
|
|
|
GLuint maxDraws = 0;
|
|
GL.glGetIntegerv(eGL_MAX_DRAW_BUFFERS, (GLint *)&maxDraws);
|
|
|
|
if(HasExt[ARB_draw_buffers_blend])
|
|
{
|
|
for(GLuint i = 0; i < RDCMIN(maxDraws, (GLuint)ARRAY_COUNT(Blends)); i++)
|
|
{
|
|
GL.glGetIntegeri_v(eGL_BLEND_EQUATION_RGB, i, (GLint *)&Blends[i].EquationRGB);
|
|
GL.glGetIntegeri_v(eGL_BLEND_EQUATION_ALPHA, i, (GLint *)&Blends[i].EquationAlpha);
|
|
|
|
GL.glGetIntegeri_v(eGL_BLEND_SRC_RGB, i, (GLint *)&Blends[i].SourceRGB);
|
|
GL.glGetIntegeri_v(eGL_BLEND_SRC_ALPHA, i, (GLint *)&Blends[i].SourceAlpha);
|
|
|
|
GL.glGetIntegeri_v(eGL_BLEND_DST_RGB, i, (GLint *)&Blends[i].DestinationRGB);
|
|
GL.glGetIntegeri_v(eGL_BLEND_DST_ALPHA, i, (GLint *)&Blends[i].DestinationAlpha);
|
|
|
|
Blends[i].Enabled = (GL.glIsEnabledi(eGL_BLEND, i) == GL_TRUE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if we don't have separate blending, then replicate across all from 0
|
|
|
|
GL.glGetIntegerv(eGL_BLEND_EQUATION_RGB, (GLint *)&Blends[0].EquationRGB);
|
|
GL.glGetIntegerv(eGL_BLEND_EQUATION_ALPHA, (GLint *)&Blends[0].EquationAlpha);
|
|
|
|
GL.glGetIntegerv(eGL_BLEND_SRC_RGB, (GLint *)&Blends[0].SourceRGB);
|
|
GL.glGetIntegerv(eGL_BLEND_SRC_ALPHA, (GLint *)&Blends[0].SourceAlpha);
|
|
|
|
GL.glGetIntegerv(eGL_BLEND_DST_RGB, (GLint *)&Blends[0].DestinationRGB);
|
|
GL.glGetIntegerv(eGL_BLEND_DST_ALPHA, (GLint *)&Blends[0].DestinationAlpha);
|
|
|
|
Blends[0].Enabled = (GL.glIsEnabled(eGL_BLEND) == GL_TRUE);
|
|
|
|
for(GLuint i = 1; i < (GLuint)ARRAY_COUNT(Blends); i++)
|
|
memcpy(&Blends[i], &Blends[0], sizeof(Blends[i]));
|
|
}
|
|
|
|
GL.glGetFloatv(eGL_BLEND_COLOR, &BlendColor[0]);
|
|
|
|
if(HasExt[ARB_viewport_array])
|
|
{
|
|
GLuint maxViews = 0;
|
|
GL.glGetIntegerv(eGL_MAX_VIEWPORTS, (GLint *)&maxViews);
|
|
|
|
for(GLuint i = 0; i < RDCMIN(maxViews, (GLuint)ARRAY_COUNT(Viewports)); i++)
|
|
GL.glGetFloati_v(eGL_VIEWPORT, i, &Viewports[i].x);
|
|
|
|
for(GLuint i = 0; i < RDCMIN(maxViews, (GLuint)ARRAY_COUNT(Scissors)); i++)
|
|
{
|
|
GL.glGetIntegeri_v(eGL_SCISSOR_BOX, i, &Scissors[i].x);
|
|
Scissors[i].enabled = (GL.glIsEnabledi(eGL_SCISSOR_TEST, i) == GL_TRUE);
|
|
}
|
|
|
|
for(GLuint i = 0; i < RDCMIN(maxViews, (GLuint)ARRAY_COUNT(DepthRanges)); i++)
|
|
{
|
|
if(IsGLES)
|
|
{
|
|
float v[2];
|
|
GL.glGetFloati_v(eGL_DEPTH_RANGE, i, v);
|
|
DepthRanges[i] = {(double)v[0], (double)v[1]};
|
|
}
|
|
else
|
|
{
|
|
GL.glGetDoublei_v(eGL_DEPTH_RANGE, i, &DepthRanges[i].nearZ);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if we don't have separate viewport/etc, then replicate across all from 0
|
|
// note that the same extension introduced indexed viewports, scissors and
|
|
// depth ranges. Convenient!
|
|
|
|
GL.glGetFloatv(eGL_VIEWPORT, &Viewports[0].x);
|
|
GL.glGetIntegerv(eGL_SCISSOR_BOX, &Scissors[0].x);
|
|
Scissors[0].enabled = (GL.glIsEnabled(eGL_SCISSOR_TEST) == GL_TRUE);
|
|
if(IsGLES)
|
|
{
|
|
float v[2];
|
|
GL.glGetFloatv(eGL_DEPTH_RANGE, v);
|
|
DepthRanges[0] = {(double)v[0], (double)v[1]};
|
|
}
|
|
else
|
|
{
|
|
GL.glGetDoublev(eGL_DEPTH_RANGE, &DepthRanges[0].nearZ);
|
|
}
|
|
|
|
for(GLuint i = 1; i < (GLuint)ARRAY_COUNT(Viewports); i++)
|
|
memcpy(&Viewports[i], &Viewports[0], sizeof(Viewports[i]));
|
|
|
|
for(GLuint i = 1; i < (GLuint)ARRAY_COUNT(Scissors); i++)
|
|
memcpy(&Scissors[i], &Scissors[0], sizeof(Scissors[i]));
|
|
|
|
for(GLuint i = 1; i < (GLuint)ARRAY_COUNT(DepthRanges); i++)
|
|
memcpy(&DepthRanges[i], &DepthRanges[0], sizeof(DepthRanges[i]));
|
|
}
|
|
|
|
{
|
|
GLuint draw, read;
|
|
GL.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint *)&draw);
|
|
GL.glGetIntegerv(eGL_READ_FRAMEBUFFER_BINDING, (GLint *)&read);
|
|
DrawFBO = FramebufferRes(ctx, draw);
|
|
ReadFBO = FramebufferRes(ctx, read);
|
|
|
|
// if the default FBO is bound, we must force the use of the context itself, rather than the
|
|
// sharegroup (if FBOs are normally shared).
|
|
if(draw == 0)
|
|
DrawFBO = FramebufferRes({ctx.ctx, ctx.ctx}, draw);
|
|
if(read == 0)
|
|
ReadFBO = FramebufferRes({ctx.ctx, ctx.ctx}, read);
|
|
}
|
|
|
|
GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, 0);
|
|
GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, 0);
|
|
|
|
for(GLuint i = 0; i < RDCMIN(maxDraws, (GLuint)ARRAY_COUNT(DrawBuffers)); i++)
|
|
GL.glGetIntegerv(GLenum(eGL_DRAW_BUFFER0 + i), (GLint *)&DrawBuffers[i]);
|
|
|
|
GL.glGetIntegerv(eGL_READ_BUFFER, (GLint *)&ReadBuffer);
|
|
|
|
GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, DrawFBO.name);
|
|
GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, ReadFBO.name);
|
|
|
|
GL.glGetIntegerv(eGL_FRAGMENT_SHADER_DERIVATIVE_HINT, (GLint *)&Hints.Derivatives);
|
|
if(!IsGLES)
|
|
{
|
|
GL.glGetIntegerv(eGL_LINE_SMOOTH_HINT, (GLint *)&Hints.LineSmooth);
|
|
GL.glGetIntegerv(eGL_POLYGON_SMOOTH_HINT, (GLint *)&Hints.PolySmooth);
|
|
GL.glGetIntegerv(eGL_TEXTURE_COMPRESSION_HINT, (GLint *)&Hints.TexCompression);
|
|
}
|
|
|
|
GL.glGetBooleanv(eGL_DEPTH_WRITEMASK, &DepthWriteMask);
|
|
GL.glGetFloatv(eGL_DEPTH_CLEAR_VALUE, &DepthClearValue);
|
|
GL.glGetIntegerv(eGL_DEPTH_FUNC, (GLint *)&DepthFunc);
|
|
|
|
if(HasExt[EXT_depth_bounds_test])
|
|
{
|
|
GL.glGetDoublev(eGL_DEPTH_BOUNDS_EXT, &DepthBounds.nearZ);
|
|
}
|
|
else
|
|
{
|
|
DepthBounds.nearZ = 0.0f;
|
|
DepthBounds.farZ = 1.0f;
|
|
}
|
|
|
|
{
|
|
GL.glGetIntegerv(eGL_STENCIL_FUNC, (GLint *)&StencilFront.func);
|
|
GL.glGetIntegerv(eGL_STENCIL_BACK_FUNC, (GLint *)&StencilBack.func);
|
|
|
|
GL.glGetIntegerv(eGL_STENCIL_REF, (GLint *)&StencilFront.ref);
|
|
GL.glGetIntegerv(eGL_STENCIL_BACK_REF, (GLint *)&StencilBack.ref);
|
|
|
|
GLint maskval;
|
|
GL.glGetIntegerv(eGL_STENCIL_VALUE_MASK, &maskval);
|
|
StencilFront.valuemask = uint8_t(maskval & 0xff);
|
|
GL.glGetIntegerv(eGL_STENCIL_BACK_VALUE_MASK, &maskval);
|
|
StencilBack.valuemask = uint8_t(maskval & 0xff);
|
|
|
|
GL.glGetIntegerv(eGL_STENCIL_WRITEMASK, &maskval);
|
|
StencilFront.writemask = uint8_t(maskval & 0xff);
|
|
GL.glGetIntegerv(eGL_STENCIL_BACK_WRITEMASK, &maskval);
|
|
StencilBack.writemask = uint8_t(maskval & 0xff);
|
|
|
|
GL.glGetIntegerv(eGL_STENCIL_FAIL, (GLint *)&StencilFront.stencilFail);
|
|
GL.glGetIntegerv(eGL_STENCIL_BACK_FAIL, (GLint *)&StencilBack.stencilFail);
|
|
|
|
GL.glGetIntegerv(eGL_STENCIL_PASS_DEPTH_FAIL, (GLint *)&StencilFront.depthFail);
|
|
GL.glGetIntegerv(eGL_STENCIL_BACK_PASS_DEPTH_FAIL, (GLint *)&StencilBack.depthFail);
|
|
|
|
GL.glGetIntegerv(eGL_STENCIL_PASS_DEPTH_PASS, (GLint *)&StencilFront.pass);
|
|
GL.glGetIntegerv(eGL_STENCIL_BACK_PASS_DEPTH_PASS, (GLint *)&StencilBack.pass);
|
|
}
|
|
|
|
GL.glGetIntegerv(eGL_STENCIL_CLEAR_VALUE, (GLint *)&StencilClearValue);
|
|
|
|
if(HasExt[EXT_draw_buffers2] || HasExt[ARB_draw_buffers_blend])
|
|
{
|
|
for(GLuint i = 0; i < RDCMIN(maxDraws, (GLuint)ARRAY_COUNT(ColorMasks)); i++)
|
|
GL.glGetBooleani_v(eGL_COLOR_WRITEMASK, i, &ColorMasks[i].red);
|
|
}
|
|
else
|
|
{
|
|
GL.glGetBooleanv(eGL_COLOR_WRITEMASK, &ColorMasks[0].red);
|
|
for(size_t i = 1; i < ARRAY_COUNT(ColorMasks); i++)
|
|
memcpy(&ColorMasks[i], &ColorMasks[0], sizeof(ColorMask));
|
|
}
|
|
|
|
if(HasExt[ARB_texture_multisample_no_array] || HasExt[ARB_texture_multisample])
|
|
GL.glGetIntegeri_v(eGL_SAMPLE_MASK_VALUE, 0, (GLint *)&SampleMask[0]);
|
|
|
|
GL.glGetFloatv(eGL_SAMPLE_COVERAGE_VALUE, &SampleCoverage);
|
|
|
|
{
|
|
GLint invert = 0;
|
|
GL.glGetIntegerv(eGL_SAMPLE_COVERAGE_INVERT, (GLint *)&invert);
|
|
SampleCoverageInvert = (invert != 0);
|
|
}
|
|
|
|
if(HasExt[ARB_sample_shading])
|
|
GL.glGetFloatv(eGL_MIN_SAMPLE_SHADING_VALUE, &MinSampleShading);
|
|
else
|
|
MinSampleShading = 0;
|
|
|
|
if(HasExt[EXT_raster_multisample])
|
|
GL.glGetIntegerv(eGL_RASTER_SAMPLES_EXT, (GLint *)&RasterSamples);
|
|
else
|
|
RasterSamples = 0;
|
|
|
|
if(HasExt[EXT_raster_multisample])
|
|
GL.glGetIntegerv(eGL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT, (GLint *)&RasterFixed);
|
|
else
|
|
RasterFixed = false;
|
|
|
|
if(!IsGLES)
|
|
GL.glGetIntegerv(eGL_LOGIC_OP_MODE, (GLint *)&LogicOp);
|
|
|
|
GL.glGetFloatv(eGL_COLOR_CLEAR_VALUE, &ColorClearValue.red);
|
|
|
|
if(HasExt[ARB_tessellation_shader])
|
|
GL.glGetIntegerv(eGL_PATCH_VERTICES, &PatchParams.numVerts);
|
|
else
|
|
PatchParams.numVerts = 3;
|
|
|
|
if(!IsGLES && HasExt[ARB_tessellation_shader])
|
|
{
|
|
GL.glGetFloatv(eGL_PATCH_DEFAULT_INNER_LEVEL, &PatchParams.defaultInnerLevel[0]);
|
|
GL.glGetFloatv(eGL_PATCH_DEFAULT_OUTER_LEVEL, &PatchParams.defaultOuterLevel[0]);
|
|
}
|
|
else
|
|
{
|
|
PatchParams.defaultInnerLevel[0] = PatchParams.defaultInnerLevel[1] = 1.0f;
|
|
PatchParams.defaultOuterLevel[0] = PatchParams.defaultOuterLevel[1] =
|
|
PatchParams.defaultOuterLevel[2] = PatchParams.defaultOuterLevel[3] = 1.0f;
|
|
}
|
|
|
|
if(!VendorCheck[VendorCheck_AMD_polygon_mode_query] && !IsGLES)
|
|
{
|
|
// This was listed in docs as enumeration[2] even though polygon mode can't be set independently
|
|
// for front
|
|
// and back faces for a while, so pass large enough array to be sure.
|
|
// AMD driver claims this doesn't exist anymore in core, so don't return any value, set to
|
|
// default GL_FILL to be safe
|
|
GLenum dummy[2] = {eGL_FILL, eGL_FILL};
|
|
GL.glGetIntegerv(eGL_POLYGON_MODE, (GLint *)&dummy);
|
|
PolygonMode = dummy[0];
|
|
}
|
|
else
|
|
{
|
|
PolygonMode = eGL_FILL;
|
|
}
|
|
|
|
GL.glGetFloatv(eGL_POLYGON_OFFSET_FACTOR, &PolygonOffset[0]);
|
|
GL.glGetFloatv(eGL_POLYGON_OFFSET_UNITS, &PolygonOffset[1]);
|
|
if(HasExt[ARB_polygon_offset_clamp])
|
|
GL.glGetFloatv(eGL_POLYGON_OFFSET_CLAMP, &PolygonOffset[2]);
|
|
else
|
|
PolygonOffset[2] = 0.0f;
|
|
|
|
GL.glGetIntegerv(eGL_FRONT_FACE, (GLint *)&FrontFace);
|
|
GL.glGetIntegerv(eGL_CULL_FACE_MODE, (GLint *)&CullFace);
|
|
|
|
if(IsGLES && (HasExt[EXT_primitive_bounding_box] || HasExt[OES_primitive_bounding_box]))
|
|
GL.glGetFloatv(eGL_PRIMITIVE_BOUNDING_BOX_EXT, (GLfloat *)&PrimitiveBoundingBox);
|
|
|
|
Unpack.Fetch(true);
|
|
|
|
ClearGLErrors();
|
|
}
|
|
|
|
void GLRenderState::ApplyState(WrappedOpenGL *driver)
|
|
{
|
|
ContextPair &ctx = driver->GetCtx();
|
|
|
|
if(!ContextPresent || ctx.ctx == NULL)
|
|
return;
|
|
|
|
for(GLuint i = 0; i < eEnabled_Count; i++)
|
|
{
|
|
if(!CheckEnableDisableParam(enable_disable_cap[i].cap))
|
|
continue;
|
|
|
|
if(Enabled[i])
|
|
GL.glEnable(enable_disable_cap[i].cap);
|
|
else
|
|
GL.glDisable(enable_disable_cap[i].cap);
|
|
}
|
|
|
|
GLuint maxTextures = 0;
|
|
GL.glGetIntegerv(eGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, (GLint *)&maxTextures);
|
|
|
|
for(GLuint i = 0; i < RDCMIN(maxTextures, (GLuint)ARRAY_COUNT(Tex2D)); i++)
|
|
{
|
|
GL.glActiveTexture(GLenum(eGL_TEXTURE0 + i));
|
|
|
|
if(!IsGLES)
|
|
GL.glBindTexture(eGL_TEXTURE_1D, Tex1D[i].name);
|
|
|
|
GL.glBindTexture(eGL_TEXTURE_2D, Tex2D[i].name);
|
|
GL.glBindTexture(eGL_TEXTURE_3D, Tex3D[i].name);
|
|
|
|
if(!IsGLES)
|
|
GL.glBindTexture(eGL_TEXTURE_1D_ARRAY, Tex1DArray[i].name);
|
|
|
|
GL.glBindTexture(eGL_TEXTURE_2D_ARRAY, Tex2DArray[i].name);
|
|
|
|
if(!IsGLES)
|
|
GL.glBindTexture(eGL_TEXTURE_RECTANGLE, TexRect[i].name);
|
|
|
|
if(HasExt[ARB_texture_buffer_object])
|
|
GL.glBindTexture(eGL_TEXTURE_BUFFER, TexBuffer[i].name);
|
|
|
|
GL.glBindTexture(eGL_TEXTURE_CUBE_MAP, TexCube[i].name);
|
|
|
|
if(HasExt[ARB_texture_multisample_no_array] || HasExt[ARB_texture_multisample])
|
|
GL.glBindTexture(eGL_TEXTURE_2D_MULTISAMPLE, Tex2DMS[i].name);
|
|
|
|
if(HasExt[ARB_texture_multisample])
|
|
GL.glBindTexture(eGL_TEXTURE_2D_MULTISAMPLE_ARRAY, Tex2DMSArray[i].name);
|
|
|
|
if(HasExt[ARB_sampler_objects])
|
|
GL.glBindSampler(i, Samplers[i].name);
|
|
|
|
if(HasExt[ARB_texture_cube_map_array])
|
|
GL.glBindTexture(eGL_TEXTURE_CUBE_MAP_ARRAY, TexCubeArray[i].name);
|
|
}
|
|
|
|
if(HasExt[ARB_shader_image_load_store])
|
|
{
|
|
GLuint maxImages = 0;
|
|
GL.glGetIntegerv(eGL_MAX_IMAGE_UNITS, (GLint *)&maxImages);
|
|
|
|
for(GLuint i = 0; i < RDCMIN(maxImages, (GLuint)ARRAY_COUNT(Images)); i++)
|
|
{
|
|
// use sanitised parameters when no image is bound
|
|
if(Images[i].res.name == 0)
|
|
GL.glBindImageTexture(i, 0, 0, GL_FALSE, 0, eGL_READ_ONLY, eGL_RGBA8);
|
|
else
|
|
GL.glBindImageTexture(i, Images[i].res.name, (GLint)Images[i].level, Images[i].layered,
|
|
(GLint)Images[i].layer, Images[i].access, Images[i].format);
|
|
}
|
|
}
|
|
|
|
GL.glActiveTexture(ActiveTexture);
|
|
|
|
if(VAO.name)
|
|
GL.glBindVertexArray(VAO.name);
|
|
else
|
|
GL.glBindVertexArray(driver->GetFakeVAO0());
|
|
|
|
if(HasExt[ARB_transform_feedback2])
|
|
GL.glBindTransformFeedback(eGL_TRANSFORM_FEEDBACK, FeedbackObj.name);
|
|
|
|
// See FetchState(). The spec says that you have to SET the right format for the shader too,
|
|
// but we couldn't query for the format so we can't set it here.
|
|
GLuint maxNumAttribs = 0;
|
|
GL.glGetIntegerv(eGL_MAX_VERTEX_ATTRIBS, (GLint *)&maxNumAttribs);
|
|
for(GLuint i = 0; i < RDCMIN(maxNumAttribs, (GLuint)ARRAY_COUNT(GenericVertexAttribs)); i++)
|
|
GL.glVertexAttrib4fv(i, &GenericVertexAttribs[i].x);
|
|
|
|
GL.glLineWidth(LineWidth);
|
|
if(!IsGLES)
|
|
{
|
|
GL.glPointParameterf(eGL_POINT_FADE_THRESHOLD_SIZE, PointFadeThresholdSize);
|
|
GL.glPointParameteri(eGL_POINT_SPRITE_COORD_ORIGIN, (GLint)PointSpriteOrigin);
|
|
GL.glPointSize(PointSize);
|
|
}
|
|
|
|
if(!IsGLES)
|
|
GL.glPrimitiveRestartIndex(PrimitiveRestartIndex);
|
|
if(GL.glClipControl && HasExt[ARB_clip_control])
|
|
GL.glClipControl(ClipOrigin, ClipDepth);
|
|
if(!IsGLES)
|
|
GL.glProvokingVertex(ProvokingVertex);
|
|
|
|
GL.glUseProgram(Program.name);
|
|
if(HasExt[ARB_separate_shader_objects])
|
|
GL.glBindProgramPipeline(Pipeline.name);
|
|
|
|
GLenum shs[] = {eGL_VERTEX_SHADER, eGL_TESS_CONTROL_SHADER, eGL_TESS_EVALUATION_SHADER,
|
|
eGL_GEOMETRY_SHADER, eGL_FRAGMENT_SHADER, eGL_COMPUTE_SHADER};
|
|
|
|
RDCCOMPILE_ASSERT(ARRAY_COUNT(shs) == ARRAY_COUNT(Subroutines),
|
|
"Subroutine array not the right size");
|
|
for(size_t s = 0; s < ARRAY_COUNT(shs); s++)
|
|
{
|
|
if(shs[s] == eGL_COMPUTE_SHADER && !HasExt[ARB_compute_shader])
|
|
continue;
|
|
|
|
if((shs[s] == eGL_TESS_CONTROL_SHADER || shs[s] == eGL_TESS_EVALUATION_SHADER) &&
|
|
!HasExt[ARB_tessellation_shader])
|
|
continue;
|
|
|
|
if(Subroutines[s].numSubroutines > 0)
|
|
GL.glUniformSubroutinesuiv(shs[s], Subroutines[s].numSubroutines, Subroutines[s].Values);
|
|
}
|
|
|
|
GL.glBindBuffer(eGL_ARRAY_BUFFER, BufferBindings[eBufIdx_Array].name);
|
|
GL.glBindBuffer(eGL_COPY_READ_BUFFER, BufferBindings[eBufIdx_Copy_Read].name);
|
|
GL.glBindBuffer(eGL_COPY_WRITE_BUFFER, BufferBindings[eBufIdx_Copy_Write].name);
|
|
GL.glBindBuffer(eGL_PIXEL_PACK_BUFFER, BufferBindings[eBufIdx_Pixel_Pack].name);
|
|
GL.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, BufferBindings[eBufIdx_Pixel_Unpack].name);
|
|
if(HasExt[ARB_texture_buffer_object])
|
|
GL.glBindBuffer(eGL_TEXTURE_BUFFER, BufferBindings[eBufIdx_Texture].name);
|
|
if(HasExt[ARB_draw_indirect])
|
|
GL.glBindBuffer(eGL_DRAW_INDIRECT_BUFFER, BufferBindings[eBufIdx_Draw_Indirect].name);
|
|
if(HasExt[ARB_compute_shader])
|
|
GL.glBindBuffer(eGL_DISPATCH_INDIRECT_BUFFER, BufferBindings[eBufIdx_Dispatch_Indirect].name);
|
|
if(HasExt[ARB_query_buffer_object])
|
|
GL.glBindBuffer(eGL_QUERY_BUFFER, BufferBindings[eBufIdx_Query].name);
|
|
if(HasExt[ARB_indirect_parameters])
|
|
GL.glBindBuffer(eGL_PARAMETER_BUFFER_ARB, BufferBindings[eBufIdx_Parameter].name);
|
|
|
|
struct
|
|
{
|
|
IdxRangeBuffer *bufs;
|
|
int count;
|
|
GLenum binding;
|
|
GLenum maxcount;
|
|
} idxBufs[] = {
|
|
{
|
|
AtomicCounter, ARRAY_COUNT(AtomicCounter), eGL_ATOMIC_COUNTER_BUFFER,
|
|
eGL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS,
|
|
},
|
|
{
|
|
ShaderStorage, ARRAY_COUNT(ShaderStorage), eGL_SHADER_STORAGE_BUFFER,
|
|
eGL_MAX_SHADER_STORAGE_BUFFER_BINDINGS,
|
|
},
|
|
{
|
|
TransformFeedback, ARRAY_COUNT(TransformFeedback), eGL_TRANSFORM_FEEDBACK_BUFFER,
|
|
eGL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
|
|
},
|
|
{
|
|
UniformBinding, ARRAY_COUNT(UniformBinding), eGL_UNIFORM_BUFFER,
|
|
eGL_MAX_UNIFORM_BUFFER_BINDINGS,
|
|
},
|
|
};
|
|
|
|
for(size_t b = 0; b < ARRAY_COUNT(idxBufs); b++)
|
|
{
|
|
// only restore buffer bindings here if we were using the default transform feedback object
|
|
if(idxBufs[b].binding == eGL_TRANSFORM_FEEDBACK_BUFFER && FeedbackObj.name)
|
|
continue;
|
|
|
|
if(idxBufs[b].binding == eGL_ATOMIC_COUNTER_BUFFER && !HasExt[ARB_shader_atomic_counters])
|
|
continue;
|
|
|
|
if(idxBufs[b].binding == eGL_SHADER_STORAGE_BUFFER && !HasExt[ARB_shader_storage_buffer_object])
|
|
continue;
|
|
|
|
if(idxBufs[b].binding == eGL_TRANSFORM_FEEDBACK_BUFFER && !HasExt[ARB_transform_feedback2])
|
|
continue;
|
|
|
|
GLint maxCount = 0;
|
|
GL.glGetIntegerv(idxBufs[b].maxcount, &maxCount);
|
|
for(int i = 0; i < idxBufs[b].count && i < maxCount; i++)
|
|
{
|
|
if(idxBufs[b].bufs[i].res.name == 0 ||
|
|
(idxBufs[b].bufs[i].start == 0 && idxBufs[b].bufs[i].size == 0))
|
|
GL.glBindBufferBase(idxBufs[b].binding, i, idxBufs[b].bufs[i].res.name);
|
|
else
|
|
GL.glBindBufferRange(idxBufs[b].binding, i, idxBufs[b].bufs[i].res.name,
|
|
(GLintptr)idxBufs[b].bufs[i].start, (GLsizeiptr)idxBufs[b].bufs[i].size);
|
|
}
|
|
}
|
|
|
|
GLuint maxDraws = 0;
|
|
GL.glGetIntegerv(eGL_MAX_DRAW_BUFFERS, (GLint *)&maxDraws);
|
|
|
|
if(HasExt[ARB_draw_buffers_blend])
|
|
{
|
|
for(GLuint i = 0; i < RDCMIN(maxDraws, (GLuint)ARRAY_COUNT(Blends)); i++)
|
|
{
|
|
// not set, possibly there were lesser draw buffers during capture
|
|
if(Blends[i].EquationRGB == eGL_NONE)
|
|
continue;
|
|
|
|
GL.glBlendFuncSeparatei(i, Blends[i].SourceRGB, Blends[i].DestinationRGB,
|
|
Blends[i].SourceAlpha, Blends[i].DestinationAlpha);
|
|
GL.glBlendEquationSeparatei(i, Blends[i].EquationRGB, Blends[i].EquationAlpha);
|
|
|
|
if(Blends[i].Enabled)
|
|
GL.glEnablei(eGL_BLEND, i);
|
|
else
|
|
GL.glDisablei(eGL_BLEND, i);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// not set, possibly there were lesser draw buffers during capture
|
|
if(Blends[0].EquationRGB != eGL_NONE)
|
|
{
|
|
GL.glBlendFuncSeparate(Blends[0].SourceRGB, Blends[0].DestinationRGB, Blends[0].SourceAlpha,
|
|
Blends[0].DestinationAlpha);
|
|
GL.glBlendEquationSeparate(Blends[0].EquationRGB, Blends[0].EquationAlpha);
|
|
|
|
if(Blends[0].Enabled)
|
|
GL.glEnable(eGL_BLEND);
|
|
else
|
|
GL.glDisable(eGL_BLEND);
|
|
}
|
|
}
|
|
|
|
GL.glBlendColor(BlendColor[0], BlendColor[1], BlendColor[2], BlendColor[3]);
|
|
|
|
if(HasExt[ARB_viewport_array])
|
|
{
|
|
GLuint maxViews = 0;
|
|
GL.glGetIntegerv(eGL_MAX_VIEWPORTS, (GLint *)&maxViews);
|
|
|
|
GL.glViewportArrayv(0, RDCMIN(maxViews, (GLuint)ARRAY_COUNT(Viewports)), &Viewports[0].x);
|
|
|
|
for(GLuint s = 0; s < RDCMIN(maxViews, (GLuint)ARRAY_COUNT(Scissors)); ++s)
|
|
{
|
|
GL.glScissorIndexedv(s, &Scissors[s].x);
|
|
|
|
if(Scissors[s].enabled)
|
|
GL.glEnablei(eGL_SCISSOR_TEST, s);
|
|
else
|
|
GL.glDisablei(eGL_SCISSOR_TEST, s);
|
|
}
|
|
|
|
for(GLuint i = 0; i < RDCMIN(maxViews, (GLuint)ARRAY_COUNT(DepthRanges)); i++)
|
|
{
|
|
if(IsGLES)
|
|
{
|
|
float v[2] = {(float)DepthRanges[i].nearZ, (float)DepthRanges[i].farZ};
|
|
GL.glDepthRangeArrayfvOES(i, 1, v);
|
|
}
|
|
else
|
|
{
|
|
GL.glDepthRangeArrayv(i, 1, &DepthRanges[i].nearZ);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GL.glViewport((GLint)Viewports[0].x, (GLint)Viewports[0].y, (GLsizei)Viewports[0].width,
|
|
(GLsizei)Viewports[0].height);
|
|
|
|
GL.glScissor(Scissors[0].x, Scissors[0].y, Scissors[0].width, Scissors[0].height);
|
|
|
|
if(Scissors[0].enabled)
|
|
GL.glEnable(eGL_SCISSOR_TEST);
|
|
else
|
|
GL.glDisable(eGL_SCISSOR_TEST);
|
|
|
|
if(IsGLES)
|
|
GL.glDepthRangef((float)DepthRanges[0].nearZ, (float)DepthRanges[0].farZ);
|
|
else
|
|
GL.glDepthRange(DepthRanges[0].nearZ, DepthRanges[0].farZ);
|
|
}
|
|
|
|
GLenum DBs[8] = {eGL_NONE};
|
|
uint32_t numDBs = 0;
|
|
for(GLuint i = 0; i < RDCMIN(maxDraws, (GLuint)ARRAY_COUNT(DrawBuffers)); i++)
|
|
{
|
|
if(DrawBuffers[i] != eGL_NONE)
|
|
{
|
|
numDBs++;
|
|
DBs[i] = DrawBuffers[i];
|
|
|
|
if(IsReplayMode(driver->GetState()))
|
|
{
|
|
// since we are faking the default framebuffer with our own
|
|
// to see the results, replace back/front/left/right with color attachment 0
|
|
if(DBs[i] == eGL_BACK_LEFT || DBs[i] == eGL_BACK_RIGHT || DBs[i] == eGL_FRONT_LEFT ||
|
|
DBs[i] == eGL_FRONT_RIGHT)
|
|
DBs[i] = eGL_COLOR_ATTACHMENT0;
|
|
|
|
// These aren't valid for glDrawBuffers but can be returned when we call glGet,
|
|
// assume they mean left implicitly
|
|
if(DBs[i] == eGL_BACK || DBs[i] == eGL_FRONT || DBs[i] == eGL_FRONT_AND_BACK)
|
|
DBs[i] = eGL_COLOR_ATTACHMENT0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// this will always return true during capture, but on replay we only do
|
|
// this work if we're on the replay context
|
|
if(driver->GetReplay()->IsReplayContext(ctx.ctx))
|
|
{
|
|
GLuint fbo = driver->GetCurrentDefaultFBO();
|
|
|
|
if(fbo)
|
|
{
|
|
// apply drawbuffers/readbuffer to default framebuffer
|
|
GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, driver->GetCurrentDefaultFBO());
|
|
GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, driver->GetCurrentDefaultFBO());
|
|
GL.glDrawBuffers(numDBs, DBs);
|
|
|
|
// see above for reasoning for this
|
|
GL.glReadBuffer(eGL_COLOR_ATTACHMENT0);
|
|
}
|
|
|
|
if(ReadFBO.name)
|
|
GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, ReadFBO.name);
|
|
else if(fbo)
|
|
GL.glBindFramebuffer(eGL_READ_FRAMEBUFFER, fbo);
|
|
|
|
if(DrawFBO.name)
|
|
GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, DrawFBO.name);
|
|
else if(fbo)
|
|
GL.glBindFramebuffer(eGL_DRAW_FRAMEBUFFER, fbo);
|
|
}
|
|
|
|
GL.glHint(eGL_FRAGMENT_SHADER_DERIVATIVE_HINT, Hints.Derivatives);
|
|
if(!IsGLES)
|
|
{
|
|
GL.glHint(eGL_LINE_SMOOTH_HINT, Hints.LineSmooth);
|
|
GL.glHint(eGL_POLYGON_SMOOTH_HINT, Hints.PolySmooth);
|
|
GL.glHint(eGL_TEXTURE_COMPRESSION_HINT, Hints.TexCompression);
|
|
}
|
|
|
|
GL.glDepthMask(DepthWriteMask);
|
|
GL.glClearDepthf(DepthClearValue);
|
|
GL.glDepthFunc(DepthFunc);
|
|
|
|
if(HasExt[EXT_depth_bounds_test] && GL.glDepthBoundsEXT)
|
|
GL.glDepthBoundsEXT(DepthBounds.nearZ, DepthBounds.farZ);
|
|
|
|
{
|
|
GL.glStencilFuncSeparate(eGL_FRONT, StencilFront.func, StencilFront.ref, StencilFront.valuemask);
|
|
GL.glStencilFuncSeparate(eGL_BACK, StencilBack.func, StencilBack.ref, StencilBack.valuemask);
|
|
|
|
GL.glStencilMaskSeparate(eGL_FRONT, StencilFront.writemask);
|
|
GL.glStencilMaskSeparate(eGL_BACK, StencilBack.writemask);
|
|
|
|
GL.glStencilOpSeparate(eGL_FRONT, StencilFront.stencilFail, StencilFront.depthFail,
|
|
StencilFront.pass);
|
|
GL.glStencilOpSeparate(eGL_BACK, StencilBack.stencilFail, StencilBack.depthFail,
|
|
StencilBack.pass);
|
|
}
|
|
|
|
GL.glClearStencil((GLint)StencilClearValue);
|
|
|
|
if(HasExt[EXT_draw_buffers2] || HasExt[ARB_draw_buffers_blend])
|
|
{
|
|
for(GLuint i = 0; i < RDCMIN(maxDraws, (GLuint)ARRAY_COUNT(ColorMasks)); i++)
|
|
GL.glColorMaski(i, ColorMasks[i].red, ColorMasks[i].green, ColorMasks[i].blue,
|
|
ColorMasks[i].alpha);
|
|
}
|
|
else
|
|
{
|
|
GL.glColorMask(ColorMasks[0].red, ColorMasks[0].green, ColorMasks[0].blue, ColorMasks[0].alpha);
|
|
}
|
|
|
|
if(HasExt[ARB_texture_multisample_no_array] || HasExt[ARB_texture_multisample])
|
|
GL.glSampleMaski(0, (GLbitfield)SampleMask[0]);
|
|
|
|
GL.glSampleCoverage(SampleCoverage, SampleCoverageInvert ? GL_TRUE : GL_FALSE);
|
|
|
|
if(HasExt[ARB_sample_shading])
|
|
GL.glMinSampleShading(MinSampleShading);
|
|
|
|
if(HasExt[EXT_raster_multisample] && GL.glRasterSamplesEXT)
|
|
GL.glRasterSamplesEXT(RasterSamples, RasterFixed);
|
|
|
|
if(!IsGLES)
|
|
GL.glLogicOp(LogicOp);
|
|
|
|
GL.glClearColor(ColorClearValue.red, ColorClearValue.green, ColorClearValue.blue,
|
|
ColorClearValue.alpha);
|
|
|
|
if(HasExt[ARB_tessellation_shader])
|
|
{
|
|
GL.glPatchParameteri(eGL_PATCH_VERTICES, PatchParams.numVerts);
|
|
if(!IsGLES)
|
|
{
|
|
GL.glPatchParameterfv(eGL_PATCH_DEFAULT_INNER_LEVEL, PatchParams.defaultInnerLevel);
|
|
GL.glPatchParameterfv(eGL_PATCH_DEFAULT_OUTER_LEVEL, PatchParams.defaultOuterLevel);
|
|
}
|
|
}
|
|
|
|
if(!IsGLES)
|
|
GL.glPolygonMode(eGL_FRONT_AND_BACK, PolygonMode);
|
|
|
|
if(HasExt[ARB_polygon_offset_clamp])
|
|
GL.glPolygonOffsetClamp(PolygonOffset[0], PolygonOffset[1], PolygonOffset[2]);
|
|
else
|
|
GL.glPolygonOffset(PolygonOffset[0], PolygonOffset[1]);
|
|
|
|
GL.glFrontFace(FrontFace);
|
|
GL.glCullFace(CullFace);
|
|
|
|
if(IsGLES && (HasExt[EXT_primitive_bounding_box] || HasExt[OES_primitive_bounding_box]))
|
|
GL.glPrimitiveBoundingBox(PrimitiveBoundingBox.minX, PrimitiveBoundingBox.minY,
|
|
PrimitiveBoundingBox.minZ, PrimitiveBoundingBox.minW,
|
|
PrimitiveBoundingBox.maxX, PrimitiveBoundingBox.maxY,
|
|
PrimitiveBoundingBox.maxZ, PrimitiveBoundingBox.maxW);
|
|
|
|
Unpack.Apply(true);
|
|
|
|
ClearGLErrors();
|
|
}
|
|
|
|
void GLRenderState::Clear()
|
|
{
|
|
ContextPresent = true;
|
|
|
|
RDCEraseEl(Enabled);
|
|
|
|
RDCEraseEl(Tex1D);
|
|
RDCEraseEl(Tex2D);
|
|
RDCEraseEl(Tex3D);
|
|
RDCEraseEl(Tex1DArray);
|
|
RDCEraseEl(Tex2DArray);
|
|
RDCEraseEl(TexCubeArray);
|
|
RDCEraseEl(TexRect);
|
|
RDCEraseEl(TexBuffer);
|
|
RDCEraseEl(TexCube);
|
|
RDCEraseEl(Tex2DMS);
|
|
RDCEraseEl(Tex2DMSArray);
|
|
RDCEraseEl(Samplers);
|
|
RDCEraseEl(ActiveTexture);
|
|
|
|
RDCEraseEl(Images);
|
|
for(GLuint i = 0; i < (GLuint)ARRAY_COUNT(Images); i++)
|
|
{
|
|
Images[i].access = eGL_READ_ONLY;
|
|
Images[i].format = eGL_RGBA8;
|
|
}
|
|
|
|
RDCEraseEl(Program);
|
|
RDCEraseEl(Pipeline);
|
|
|
|
RDCEraseEl(Subroutines);
|
|
|
|
RDCEraseEl(VAO);
|
|
RDCEraseEl(FeedbackObj);
|
|
|
|
RDCEraseEl(GenericVertexAttribs);
|
|
|
|
RDCEraseEl(PointFadeThresholdSize);
|
|
RDCEraseEl(PointSpriteOrigin);
|
|
RDCEraseEl(LineWidth);
|
|
RDCEraseEl(PointSize);
|
|
|
|
RDCEraseEl(PrimitiveRestartIndex);
|
|
RDCEraseEl(PrimitiveBoundingBox);
|
|
RDCEraseEl(ClipOrigin);
|
|
RDCEraseEl(ClipDepth);
|
|
RDCEraseEl(ProvokingVertex);
|
|
|
|
RDCEraseEl(BufferBindings);
|
|
RDCEraseEl(AtomicCounter);
|
|
RDCEraseEl(ShaderStorage);
|
|
RDCEraseEl(TransformFeedback);
|
|
RDCEraseEl(UniformBinding);
|
|
RDCEraseEl(Blends);
|
|
RDCEraseEl(BlendColor);
|
|
RDCEraseEl(Viewports);
|
|
RDCEraseEl(Scissors);
|
|
|
|
RDCEraseEl(DrawFBO);
|
|
RDCEraseEl(ReadFBO);
|
|
RDCEraseEl(DrawBuffers);
|
|
RDCEraseEl(ReadBuffer);
|
|
|
|
RDCEraseEl(PatchParams);
|
|
RDCEraseEl(PolygonMode);
|
|
RDCEraseEl(PolygonOffset);
|
|
|
|
RDCEraseEl(DepthWriteMask);
|
|
RDCEraseEl(DepthClearValue);
|
|
RDCEraseEl(DepthRanges);
|
|
RDCEraseEl(DepthBounds);
|
|
RDCEraseEl(DepthFunc);
|
|
RDCEraseEl(StencilFront);
|
|
RDCEraseEl(StencilBack);
|
|
RDCEraseEl(StencilClearValue);
|
|
RDCEraseEl(ColorMasks);
|
|
RDCEraseEl(SampleMask);
|
|
RDCEraseEl(RasterSamples);
|
|
RDCEraseEl(RasterFixed);
|
|
RDCEraseEl(SampleCoverage);
|
|
RDCEraseEl(SampleCoverageInvert);
|
|
RDCEraseEl(MinSampleShading);
|
|
RDCEraseEl(LogicOp);
|
|
RDCEraseEl(ColorClearValue);
|
|
|
|
RDCEraseEl(Hints);
|
|
RDCEraseEl(FrontFace);
|
|
RDCEraseEl(CullFace);
|
|
|
|
RDCEraseEl(Unpack);
|
|
}
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, GLRenderState::Image &el)
|
|
{
|
|
SERIALISE_MEMBER(res);
|
|
SERIALISE_MEMBER(level);
|
|
SERIALISE_MEMBER(layered);
|
|
SERIALISE_MEMBER(layer);
|
|
SERIALISE_MEMBER(access);
|
|
SERIALISE_MEMBER(format);
|
|
}
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, GLRenderState::Subroutine &el)
|
|
{
|
|
SERIALISE_MEMBER(numSubroutines);
|
|
SERIALISE_MEMBER(Values);
|
|
}
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, GLRenderState::IdxRangeBuffer &el)
|
|
{
|
|
SERIALISE_MEMBER(res);
|
|
SERIALISE_MEMBER(start);
|
|
SERIALISE_MEMBER(size);
|
|
}
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, GLRenderState::BlendState &el)
|
|
{
|
|
SERIALISE_MEMBER(EquationRGB);
|
|
SERIALISE_MEMBER(EquationAlpha);
|
|
SERIALISE_MEMBER(SourceRGB);
|
|
SERIALISE_MEMBER(SourceAlpha);
|
|
SERIALISE_MEMBER(DestinationRGB);
|
|
SERIALISE_MEMBER(DestinationAlpha);
|
|
SERIALISE_MEMBER(Enabled);
|
|
}
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, GLRenderState::Viewport &el)
|
|
{
|
|
SERIALISE_MEMBER(x);
|
|
SERIALISE_MEMBER(y);
|
|
SERIALISE_MEMBER(width);
|
|
SERIALISE_MEMBER(height);
|
|
}
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, GLRenderState::Scissor &el)
|
|
{
|
|
SERIALISE_MEMBER(x);
|
|
SERIALISE_MEMBER(y);
|
|
SERIALISE_MEMBER(width);
|
|
SERIALISE_MEMBER(height);
|
|
SERIALISE_MEMBER(enabled);
|
|
}
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, GLRenderState::DepthRange &el)
|
|
{
|
|
SERIALISE_MEMBER(nearZ);
|
|
SERIALISE_MEMBER(farZ);
|
|
}
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, GLRenderState::DepthBound &el)
|
|
{
|
|
SERIALISE_MEMBER(nearZ);
|
|
SERIALISE_MEMBER(farZ);
|
|
}
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, GLRenderState::ColorMask &el)
|
|
{
|
|
SERIALISE_MEMBER(red);
|
|
SERIALISE_MEMBER(green);
|
|
SERIALISE_MEMBER(blue);
|
|
SERIALISE_MEMBER(alpha);
|
|
}
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, GLRenderState::ClearValue &el)
|
|
{
|
|
SERIALISE_MEMBER(red);
|
|
SERIALISE_MEMBER(green);
|
|
SERIALISE_MEMBER(blue);
|
|
SERIALISE_MEMBER(alpha);
|
|
}
|
|
|
|
template <class SerialiserType>
|
|
void DoSerialise(SerialiserType &ser, GLRenderState &el)
|
|
{
|
|
SERIALISE_MEMBER(ContextPresent);
|
|
|
|
if(!el.ContextPresent)
|
|
return;
|
|
|
|
RDCCOMPILE_ASSERT(GLRenderState::eEnabled_Count == 34, "Update cosmetic enabled serialisation");
|
|
|
|
for(int i = 0; i < GLRenderState::eEnabled_Count; i++)
|
|
ser.Serialise(enable_disable_cap[i].name, el.Enabled[i]);
|
|
|
|
ser.Serialise("GL_TEXTURE_BINDING_1D"_lit, el.Tex1D);
|
|
ser.Serialise("GL_TEXTURE_BINDING_2D"_lit, el.Tex2D);
|
|
ser.Serialise("GL_TEXTURE_BINDING_3D"_lit, el.Tex3D);
|
|
ser.Serialise("GL_TEXTURE_BINDING_1D_ARRAY"_lit, el.Tex1DArray);
|
|
ser.Serialise("GL_TEXTURE_BINDING_2D_ARRAY"_lit, el.Tex2DArray);
|
|
ser.Serialise("GL_TEXTURE_BINDING_CUBE_MAP_ARRAY"_lit, el.TexCubeArray);
|
|
ser.Serialise("GL_TEXTURE_BINDING_RECTANGLE"_lit, el.TexRect);
|
|
ser.Serialise("GL_TEXTURE_BINDING_BUFFER"_lit, el.TexBuffer);
|
|
ser.Serialise("GL_TEXTURE_BINDING_CUBE_MAP"_lit, el.TexCube);
|
|
ser.Serialise("GL_TEXTURE_BINDING_2D_MULTISAMPLE"_lit, el.Tex2DMS);
|
|
ser.Serialise("GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY"_lit, el.Tex2DMSArray);
|
|
|
|
ser.Serialise("GL_SAMPLER_BINDING"_lit, el.Samplers);
|
|
|
|
ser.Serialise("GL_ACTIVE_TEXTURE"_lit, el.ActiveTexture);
|
|
|
|
ser.Serialise("GL_IMAGE_BINDING"_lit, el.Images);
|
|
|
|
ser.Serialise("GL_CURRENT_PROGRAM"_lit, el.Program);
|
|
ser.Serialise("GL_PROGRAM_PIPELINE_BINDING"_lit, el.Pipeline);
|
|
|
|
ser.Serialise("GL_SUBROUTINES"_lit, el.Subroutines);
|
|
|
|
ser.Serialise("GL_VERTEX_ARRAY_BINDING"_lit, el.VAO);
|
|
|
|
ser.Serialise("GL_TRANSFORM_FEEDBACK_BINDING"_lit, el.FeedbackObj);
|
|
|
|
ser.Serialise("GL_CURRENT_VERTEX_ATTRIB"_lit, el.GenericVertexAttribs);
|
|
|
|
ser.Serialise("GL_POINT_FADE_THRESHOLD_SIZE"_lit, el.PointFadeThresholdSize);
|
|
ser.Serialise("GL_POINT_SPRITE_COORD_ORIGIN"_lit, el.PointSpriteOrigin);
|
|
ser.Serialise("GL_LINE_WIDTH"_lit, el.LineWidth);
|
|
ser.Serialise("GL_POINT_SIZE"_lit, el.PointSize);
|
|
|
|
ser.Serialise("GL_PRIMITIVE_RESTART_INDEX"_lit, el.PrimitiveRestartIndex);
|
|
|
|
{
|
|
ser.Serialise("GL_PRIMITIVE_BOUNDING_BOX_MINX"_lit, el.PrimitiveBoundingBox.minX);
|
|
ser.Serialise("GL_PRIMITIVE_BOUNDING_BOX_MINY"_lit, el.PrimitiveBoundingBox.minY);
|
|
ser.Serialise("GL_PRIMITIVE_BOUNDING_BOX_MINZ"_lit, el.PrimitiveBoundingBox.minZ);
|
|
ser.Serialise("GL_PRIMITIVE_BOUNDING_BOX_MINW"_lit, el.PrimitiveBoundingBox.minW);
|
|
ser.Serialise("GL_PRIMITIVE_BOUNDING_BOX_MAXX"_lit, el.PrimitiveBoundingBox.maxX);
|
|
ser.Serialise("GL_PRIMITIVE_BOUNDING_BOX_MAXY"_lit, el.PrimitiveBoundingBox.maxY);
|
|
ser.Serialise("GL_PRIMITIVE_BOUNDING_BOX_MAXZ"_lit, el.PrimitiveBoundingBox.maxZ);
|
|
ser.Serialise("GL_PRIMITIVE_BOUNDING_BOX_MAXW"_lit, el.PrimitiveBoundingBox.maxW);
|
|
}
|
|
|
|
ser.Serialise("GL_CLIP_ORIGIN"_lit, el.ClipOrigin);
|
|
ser.Serialise("GL_CLIP_DEPTH_MODE"_lit, el.ClipDepth);
|
|
ser.Serialise("GL_PROVOKING_VERTEX"_lit, el.ProvokingVertex);
|
|
|
|
ser.Serialise("GL_ARRAY_BUFFER_BINDING"_lit, el.BufferBindings[GLRenderState::eBufIdx_Array]);
|
|
ser.Serialise("GL_COPY_READ_BUFFER_BINDING"_lit,
|
|
el.BufferBindings[GLRenderState::eBufIdx_Copy_Read]);
|
|
ser.Serialise("GL_COPY_WRITE_BUFFER_BINDING"_lit,
|
|
el.BufferBindings[GLRenderState::eBufIdx_Copy_Write]);
|
|
ser.Serialise("GL_PIXEL_PACK_BUFFER_BINDING"_lit,
|
|
el.BufferBindings[GLRenderState::eBufIdx_Pixel_Pack]);
|
|
ser.Serialise("GL_PIXEL_UNPACK_BUFFER_BINDING"_lit,
|
|
el.BufferBindings[GLRenderState::eBufIdx_Pixel_Unpack]);
|
|
ser.Serialise("GL_TEXTURE_BUFFER_BINDING"_lit, el.BufferBindings[GLRenderState::eBufIdx_Texture]);
|
|
ser.Serialise("GL_DRAW_INDIRECT_BUFFER_BINDING"_lit,
|
|
el.BufferBindings[GLRenderState::eBufIdx_Draw_Indirect]);
|
|
ser.Serialise("GL_DISPATCH_INDIRECT_BUFFER_BINDING"_lit,
|
|
el.BufferBindings[GLRenderState::eBufIdx_Dispatch_Indirect]);
|
|
ser.Serialise("GL_QUERY_BUFFER_BINDING"_lit, el.BufferBindings[GLRenderState::eBufIdx_Query]);
|
|
ser.Serialise("GL_PARAMETER_BUFFER_ARB_BINDING"_lit,
|
|
el.BufferBindings[GLRenderState::eBufIdx_Parameter]);
|
|
|
|
ser.Serialise("GL_ATOMIC_COUNTER_BUFFER_BINDING"_lit, el.AtomicCounter);
|
|
ser.Serialise("GL_SHADER_STORAGE_BUFFER_BINDING"_lit, el.ShaderStorage);
|
|
ser.Serialise("GL_TRANSFORM_FEEDBACK_BUFFER_BINDING"_lit, el.TransformFeedback);
|
|
ser.Serialise("GL_UNIFORM_BUFFER_BINDING"_lit, el.UniformBinding);
|
|
|
|
ser.Serialise("GL_BLENDS"_lit, el.Blends);
|
|
ser.Serialise("GL_BLEND_COLOR"_lit, el.BlendColor);
|
|
|
|
ser.Serialise("GL_VIEWPORT"_lit, el.Viewports);
|
|
ser.Serialise("GL_SCISSOR"_lit, el.Scissors);
|
|
|
|
ser.Serialise("GL_DEPTH_RANGE"_lit, el.DepthRanges);
|
|
|
|
ser.Serialise("GL_READ_FRAMEBUFFER_BINDING"_lit, el.ReadFBO);
|
|
ser.Serialise("GL_DRAW_FRAMEBUFFER_BINDING"_lit, el.DrawFBO);
|
|
|
|
ser.Serialise("GL_READ_BUFFER"_lit, el.ReadBuffer);
|
|
ser.Serialise("GL_DRAW_BUFFERS"_lit, el.DrawBuffers);
|
|
|
|
{
|
|
ser.Serialise("GL_PATCH_VERTICES"_lit, el.PatchParams.numVerts);
|
|
ser.Serialise("GL_PATCH_DEFAULT_INNER_LEVEL"_lit, el.PatchParams.defaultInnerLevel);
|
|
ser.Serialise("GL_PATCH_DEFAULT_OUTER_LEVEL"_lit, el.PatchParams.defaultOuterLevel);
|
|
}
|
|
|
|
ser.Serialise("GL_POLYGON_MODE"_lit, el.PolygonMode);
|
|
ser.Serialise("GL_POLYGON_OFFSET_FACTOR"_lit, el.PolygonOffset[0]);
|
|
ser.Serialise("GL_POLYGON_OFFSET_UNITS"_lit, el.PolygonOffset[1]);
|
|
ser.Serialise("GL_POLYGON_OFFSET_CLAMP_EXT"_lit, el.PolygonOffset[2]);
|
|
|
|
ser.Serialise("GL_DEPTH_WRITEMASK"_lit, el.DepthWriteMask);
|
|
ser.Serialise("GL_DEPTH_CLEAR_VALUE"_lit, el.DepthClearValue);
|
|
ser.Serialise("GL_DEPTH_FUNC"_lit, el.DepthFunc);
|
|
|
|
ser.Serialise("GL_DEPTH_BOUNDS_EXT"_lit, el.DepthBounds);
|
|
|
|
{
|
|
ser.Serialise("GL_STENCIL_FUNC"_lit, el.StencilFront.func);
|
|
ser.Serialise("GL_STENCIL_BACK_FUNC"_lit, el.StencilBack.func);
|
|
|
|
ser.Serialise("GL_STENCIL_REF"_lit, el.StencilFront.ref);
|
|
ser.Serialise("GL_STENCIL_BACK_REF"_lit, el.StencilBack.ref);
|
|
|
|
ser.Serialise("GL_STENCIL_VALUE_MASK"_lit, el.StencilFront.valuemask);
|
|
ser.Serialise("GL_STENCIL_BACK_VALUE_MASK"_lit, el.StencilBack.valuemask);
|
|
|
|
ser.Serialise("GL_STENCIL_WRITEMASK"_lit, el.StencilFront.writemask);
|
|
ser.Serialise("GL_STENCIL_BACK_WRITEMASK"_lit, el.StencilBack.writemask);
|
|
|
|
ser.Serialise("GL_STENCIL_FAIL"_lit, el.StencilFront.stencilFail);
|
|
ser.Serialise("GL_STENCIL_BACK_FAIL"_lit, el.StencilBack.stencilFail);
|
|
|
|
ser.Serialise("GL_STENCIL_PASS_DEPTH_FAIL"_lit, el.StencilFront.depthFail);
|
|
ser.Serialise("GL_STENCIL_BACK_PASS_DEPTH_FAIL"_lit, el.StencilBack.depthFail);
|
|
|
|
ser.Serialise("GL_STENCIL_PASS_DEPTH_PASS"_lit, el.StencilFront.pass);
|
|
ser.Serialise("GL_STENCIL_BACK_PASS_DEPTH_PASS"_lit, el.StencilBack.pass);
|
|
}
|
|
|
|
ser.Serialise("GL_STENCIL_CLEAR_VALUE"_lit, el.StencilClearValue);
|
|
|
|
ser.Serialise("GL_COLOR_WRITEMASK"_lit, el.ColorMasks);
|
|
|
|
ser.Serialise("GL_RASTER_SAMPLES_EXT"_lit, el.RasterSamples);
|
|
ser.Serialise("GL_RASTER_FIXED_SAMPLE_LOCATIONS_EXT"_lit, el.RasterFixed);
|
|
|
|
ser.Serialise("GL_SAMPLE_MASK_VALUE"_lit, el.SampleMask);
|
|
ser.Serialise("GL_SAMPLE_COVERAGE_VALUE"_lit, el.SampleCoverage);
|
|
ser.Serialise("GL_SAMPLE_COVERAGE_INVERT"_lit, el.SampleCoverageInvert);
|
|
ser.Serialise("GL_MIN_SAMPLE_SHADING"_lit, el.MinSampleShading);
|
|
|
|
ser.Serialise("GL_LOGIC_OP_MODE"_lit, el.LogicOp);
|
|
|
|
ser.Serialise("GL_COLOR_CLEAR_VALUE"_lit, el.ColorClearValue);
|
|
|
|
ser.Serialise("GL_FRAGMENT_SHADER_DERIVATIVE_HINT"_lit, el.Hints.Derivatives);
|
|
ser.Serialise("GL_LINE_SMOOTH_HINT"_lit, el.Hints.LineSmooth);
|
|
ser.Serialise("GL_POLYGON_SMOOTH_HINT"_lit, el.Hints.PolySmooth);
|
|
ser.Serialise("GL_TEXTURE_COMPRESSION_HINT"_lit, el.Hints.TexCompression);
|
|
|
|
ser.Serialise("GL_FRONT_FACE"_lit, el.FrontFace);
|
|
ser.Serialise("GL_CULL_FACE_MODE"_lit, el.CullFace);
|
|
|
|
ser.Serialise("GL_UNPACK_SWAP_BYTES"_lit, el.Unpack.swapBytes);
|
|
// TODO serialise GL_UNPACK_LSB_FIRST?
|
|
ser.Serialise("GL_UNPACK_ROW_LENGTH"_lit, el.Unpack.rowlength);
|
|
ser.Serialise("GL_UNPACK_IMAGE_HEIGHT"_lit, el.Unpack.imageheight);
|
|
ser.Serialise("GL_UNPACK_SKIP_PIXELS"_lit, el.Unpack.skipPixels);
|
|
ser.Serialise("GL_UNPACK_SKIP_ROWS"_lit, el.Unpack.skipRows);
|
|
ser.Serialise("GL_UNPACK_SKIP_IMAGES"_lit, el.Unpack.skipImages);
|
|
ser.Serialise("GL_UNPACK_ALIGNMENT"_lit, el.Unpack.alignment);
|
|
ser.Serialise("GL_UNPACK_COMPRESSED_BLOCK_WIDTH"_lit, el.Unpack.compressedBlockWidth);
|
|
ser.Serialise("GL_UNPACK_COMPRESSED_BLOCK_HEIGHT"_lit, el.Unpack.compressedBlockHeight);
|
|
ser.Serialise("GL_UNPACK_COMPRESSED_BLOCK_DEPTH"_lit, el.Unpack.compressedBlockDepth);
|
|
ser.Serialise("GL_UNPACK_COMPRESSED_BLOCK_SIZE"_lit, el.Unpack.compressedBlockSize);
|
|
}
|
|
|
|
INSTANTIATE_SERIALISE_TYPE(GLRenderState);
|