Commit 5c0e6e52 by Jamie Madill Committed by Commit Bot

Capture/Replay: Implement more state for mid-execution replay.

Includes much more state serialization. Notably Vertex Arrays were missing as well as multiple GL render states. Also fixes many serialization bugs. For example, we would not be using the correct client array and pack/unpack state in the mid-execution capture. Also depth/stencil attachments were missing from the capture. Also fixes the replay sample to work with non-zero starting frames. With these fixes we can run mid-execution replay of the T-Rex demo. Bug: angleproject:3611 Change-Id: I6945eb9b30a5137be996956b43f074a0a750b333 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/1895112 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com>
parent 405d4cf3
...@@ -24,6 +24,8 @@ class CaptureReplaySample : public SampleApplication ...@@ -24,6 +24,8 @@ class CaptureReplaySample : public SampleApplication
return false; return false;
SetBinaryDataDir(ANGLE_CAPTURE_REPLAY_SAMPLE_DATA_DIR); SetBinaryDataDir(ANGLE_CAPTURE_REPLAY_SAMPLE_DATA_DIR);
SetupContext1Replay(); SetupContext1Replay();
eglSwapInterval(getDisplay(), 1);
return true; return true;
} }
...@@ -31,7 +33,10 @@ class CaptureReplaySample : public SampleApplication ...@@ -31,7 +33,10 @@ class CaptureReplaySample : public SampleApplication
void draw() override void draw() override
{ {
ReplayContext1Frame(kReplayFrameStart + (mCurrentFrame % kReplayFrameEnd)); // Compute the current frame, looping from kReplayFrameStart to kReplayFrameEnd.
uint32_t frame =
kReplayFrameStart + (mCurrentFrame % (kReplayFrameEnd - kReplayFrameStart));
ReplayContext1Frame(frame);
mCurrentFrame++; mCurrentFrame++;
} }
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "libANGLE/capture_gles_2_0_autogen.h" #include "libANGLE/capture_gles_2_0_autogen.h"
#include "libANGLE/capture_gles_3_0_autogen.h" #include "libANGLE/capture_gles_3_0_autogen.h"
#include "libANGLE/gl_enum_utils.h" #include "libANGLE/gl_enum_utils.h"
#include "libANGLE/queryconversions.h"
#include "libANGLE/queryutils.h" #include "libANGLE/queryutils.h"
#if !ANGLE_CAPTURE_ENABLED #if !ANGLE_CAPTURE_ENABLED
...@@ -862,12 +863,24 @@ void MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> *callsOut) ...@@ -862,12 +863,24 @@ void MaybeCaptureUpdateResourceIDs(std::vector<CallCapture> *callsOut)
} }
} }
bool IsDefaultCurrentValue(const gl::VertexAttribCurrentValueData &currentValue)
{
if (currentValue.Type != gl::VertexAttribType::Float)
return false;
return currentValue.Values.FloatValues[0] == 0.0f &&
currentValue.Values.FloatValues[1] == 0.0f &&
currentValue.Values.FloatValues[2] == 0.0f && currentValue.Values.FloatValues[3] == 1.0f;
}
void CaptureMidExecutionSetup(const gl::Context *context, void CaptureMidExecutionSetup(const gl::Context *context,
std::vector<CallCapture> *setupCalls, std::vector<CallCapture> *setupCalls,
const ShaderSourceMap &cachedShaderSources, const ShaderSourceMap &cachedShaderSources,
const ProgramSourceMap &cachedProgramSources) const ProgramSourceMap &cachedProgramSources)
{ {
const gl::State &glState = context->getState(); const gl::State &apiState = context->getState();
gl::State replayState(0, nullptr, nullptr, nullptr, EGL_OPENGL_ES_API,
apiState.getClientVersion(), false, true, true, true, false);
// Small helper function to make the code more readable. // Small helper function to make the code more readable.
auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); }; auto cap = [setupCalls](CallCapture &&call) { setupCalls->emplace_back(std::move(call)); };
...@@ -876,10 +889,8 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -876,10 +889,8 @@ void CaptureMidExecutionSetup(const gl::Context *context,
// TODO(jmadill): Use handle mapping for captured objects. http://anglebug.com/3662 // TODO(jmadill): Use handle mapping for captured objects. http://anglebug.com/3662
// Capture Buffer data. // Capture Buffer data.
const gl::BufferManager &buffers = glState.getBufferManagerForCapture(); const gl::BufferManager &buffers = apiState.getBufferManagerForCapture();
const gl::BoundBufferMap &boundBuffers = glState.getBoundBuffersForCapture(); const gl::BoundBufferMap &boundBuffers = apiState.getBoundBuffersForCapture();
gl::BufferID currentArrayBuffer = {0};
for (const auto &bufferIter : buffers) for (const auto &bufferIter : buffers)
{ {
...@@ -902,21 +913,78 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -902,21 +913,78 @@ void CaptureMidExecutionSetup(const gl::Context *context,
GL_MAP_READ_BIT); GL_MAP_READ_BIT);
// Generate binding. // Generate binding.
cap(CaptureGenBuffers(glState, true, 1, &id)); cap(CaptureGenBuffers(replayState, true, 1, &id));
MaybeCaptureUpdateResourceIDs(setupCalls); MaybeCaptureUpdateResourceIDs(setupCalls);
// Always use the array buffer binding point to upload data to keep things simple. // Always use the array buffer binding point to upload data to keep things simple.
cap(CaptureBindBuffer(glState, true, gl::BufferBinding::Array, id)); if (buffer != replayState.getArrayBuffer())
cap(CaptureBufferData(glState, true, gl::BufferBinding::Array, {
replayState.setBufferBinding(context, gl::BufferBinding::Array, buffer);
cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, id));
}
cap(CaptureBufferData(replayState, true, gl::BufferBinding::Array,
static_cast<GLsizeiptr>(buffer->getSize()), buffer->getMapPointer(), static_cast<GLsizeiptr>(buffer->getSize()), buffer->getMapPointer(),
buffer->getUsage())); buffer->getUsage()));
currentArrayBuffer = id;
GLboolean dontCare; GLboolean dontCare;
(void)buffer->unmap(context, &dontCare); (void)buffer->unmap(context, &dontCare);
} }
// Vertex input states. Only handles GLES 2.0 states right now.
// Must happen after buffer data initialization.
// TODO(http://anglebug.com/3662): Complete state capture.
const std::vector<gl::VertexAttribCurrentValueData> &currentValues =
apiState.getVertexAttribCurrentValues();
const std::vector<gl::VertexAttribute> &vertexAttribs =
apiState.getVertexArray()->getVertexAttributes();
const std::vector<gl::VertexBinding> &vertexBindings =
apiState.getVertexArray()->getVertexBindings();
for (GLuint attribIndex = 0; attribIndex < gl::MAX_VERTEX_ATTRIBS; ++attribIndex)
{
const gl::VertexAttribCurrentValueData &currentValue = currentValues[attribIndex];
if (!IsDefaultCurrentValue(currentValue))
{
cap(CaptureVertexAttrib4fv(replayState, true, attribIndex,
currentValue.Values.FloatValues));
}
const gl::VertexAttribute &attrib = vertexAttribs[attribIndex];
const gl::VertexBinding &binding = vertexBindings[attrib.bindingIndex];
const gl::VertexAttribute defaultAttrib(attribIndex);
const gl::VertexBinding defaultBinding;
if (attrib.enabled != defaultAttrib.enabled)
{
cap(CaptureEnableVertexAttribArray(replayState, false, attribIndex));
}
if (attrib.format != defaultAttrib.format || attrib.pointer != defaultAttrib.pointer ||
binding.getStride() != defaultBinding.getStride() ||
binding.getBuffer().get() != nullptr)
{
gl::Buffer *buffer = binding.getBuffer().get();
if (buffer != replayState.getArrayBuffer())
{
replayState.setBufferBinding(context, gl::BufferBinding::Array, buffer);
cap(CaptureBindBuffer(replayState, true, gl::BufferBinding::Array, buffer->id()));
}
cap(CaptureVertexAttribPointer(replayState, true, attribIndex,
attrib.format->channelCount,
attrib.format->vertexAttribType, attrib.format->isNorm(),
binding.getStride(), attrib.pointer));
}
if (binding.getDivisor() != 0)
{
cap(CaptureVertexAttribDivisor(replayState, true, attribIndex, binding.getDivisor()));
}
}
// Capture Buffer bindings. // Capture Buffer bindings.
for (gl::BufferBinding binding : angle::AllEnums<gl::BufferBinding>()) for (gl::BufferBinding binding : angle::AllEnums<gl::BufferBinding>())
{ {
...@@ -925,16 +993,25 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -925,16 +993,25 @@ void CaptureMidExecutionSetup(const gl::Context *context,
// Filter out redundant buffer binding commands. Note that the code in the previous section // Filter out redundant buffer binding commands. Note that the code in the previous section
// only binds to ARRAY_BUFFER. Therefore we only check the array binding against the binding // only binds to ARRAY_BUFFER. Therefore we only check the array binding against the binding
// we set earlier. // we set earlier.
bool isArray = binding == gl::BufferBinding::Array; bool isArray = binding == gl::BufferBinding::Array;
if ((isArray && currentArrayBuffer != bufferID) || (!isArray && bufferID.value != 0)) const gl::Buffer *arrayBuffer = replayState.getArrayBuffer();
if ((isArray && arrayBuffer->id() != bufferID) || (!isArray && bufferID.value != 0))
{ {
cap(CaptureBindBuffer(glState, true, binding, bufferID)); cap(CaptureBindBuffer(replayState, true, binding, bufferID));
} }
} }
// Set a pack alignment of 1.
gl::PixelPackState &currentPackState = replayState.getPackState();
if (currentPackState.alignment != 1)
{
cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT, 1));
currentPackState.alignment = 1;
}
// Capture Texture setup and data. // Capture Texture setup and data.
const gl::TextureManager &textures = glState.getTextureManagerForCapture(); const gl::TextureManager &textures = apiState.getTextureManagerForCapture();
const gl::TextureBindingMap &boundTextures = glState.getBoundTexturesForCapture(); const gl::TextureBindingMap &boundTextures = apiState.getBoundTexturesForCapture();
gl::TextureTypeMap<gl::TextureID> currentTextureBindings; gl::TextureTypeMap<gl::TextureID> currentTextureBindings;
...@@ -949,9 +1026,9 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -949,9 +1026,9 @@ void CaptureMidExecutionSetup(const gl::Context *context,
} }
// Gen the Texture. // Gen the Texture.
cap(CaptureGenTextures(glState, true, 1, &id)); cap(CaptureGenTextures(replayState, true, 1, &id));
MaybeCaptureUpdateResourceIDs(setupCalls); MaybeCaptureUpdateResourceIDs(setupCalls);
cap(CaptureBindTexture(glState, true, texture->getType(), id)); cap(CaptureBindTexture(replayState, true, texture->getType(), id));
currentTextureBindings[texture->getType()] = id; currentTextureBindings[texture->getType()] = id;
...@@ -961,8 +1038,8 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -961,8 +1038,8 @@ void CaptureMidExecutionSetup(const gl::Context *context,
gl::SamplerState::CreateDefaultForTarget(texture->getType()); gl::SamplerState::CreateDefaultForTarget(texture->getType());
const gl::SamplerState &textureSamplerState = texture->getSamplerState(); const gl::SamplerState &textureSamplerState = texture->getSamplerState();
auto capTexParam = [cap, &glState, texture](GLenum pname, GLint param) { auto capTexParam = [cap, &replayState, texture](GLenum pname, GLint param) {
cap(CaptureTexParameteri(glState, true, texture->getType(), pname, param)); cap(CaptureTexParameteri(replayState, true, texture->getType(), pname, param));
}; };
if (textureSamplerState.getMinFilter() != defaultSamplerState.getMinFilter()) if (textureSamplerState.getMinFilter() != defaultSamplerState.getMinFilter())
...@@ -1056,13 +1133,13 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1056,13 +1133,13 @@ void CaptureMidExecutionSetup(const gl::Context *context,
(void)texture->getTexImage(context, packState, nullptr, index.getTarget(), (void)texture->getTexImage(context, packState, nullptr, index.getTarget(),
index.getLevelIndex(), getFormat, getType, data.data()); index.getLevelIndex(), getFormat, getType, data.data());
cap(CaptureTexImage2D(glState, true, index.getTarget(), index.getLevelIndex(), cap(CaptureTexImage2D(replayState, true, index.getTarget(), index.getLevelIndex(),
internalFormat, desc.size.width, desc.size.height, 0, internalFormat, desc.size.width, desc.size.height, 0,
getFormat, getType, data.data())); getFormat, getType, data.data()));
} }
else else
{ {
cap(CaptureTexImage2D(glState, true, index.getTarget(), index.getLevelIndex(), cap(CaptureTexImage2D(replayState, true, index.getTarget(), index.getLevelIndex(),
format.internalFormat, desc.size.width, desc.size.height, 0, format.internalFormat, desc.size.width, desc.size.height, 0,
format.format, format.type, nullptr)); format.format, format.type, nullptr));
} }
...@@ -1082,14 +1159,14 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1082,14 +1159,14 @@ void CaptureMidExecutionSetup(const gl::Context *context,
{ {
if (currentActiveTexture != bindingIndex) if (currentActiveTexture != bindingIndex)
{ {
cap(CaptureActiveTexture(glState, true, cap(CaptureActiveTexture(replayState, true,
GL_TEXTURE0 + static_cast<GLenum>(bindingIndex))); GL_TEXTURE0 + static_cast<GLenum>(bindingIndex)));
currentActiveTexture = bindingIndex; currentActiveTexture = bindingIndex;
} }
if (currentTextureBindings[textureType] != textureID) if (currentTextureBindings[textureType] != textureID)
{ {
cap(CaptureBindTexture(glState, true, textureType, textureID)); cap(CaptureBindTexture(replayState, true, textureType, textureID));
currentTextureBindings[textureType] = textureID; currentTextureBindings[textureType] = textureID;
} }
} }
...@@ -1097,15 +1174,15 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1097,15 +1174,15 @@ void CaptureMidExecutionSetup(const gl::Context *context,
} }
// Set active Texture. // Set active Texture.
size_t stateActiveTexture = glState.getActiveSampler(); size_t stateActiveTexture = apiState.getActiveSampler();
if (currentActiveTexture != stateActiveTexture) if (currentActiveTexture != stateActiveTexture)
{ {
cap(CaptureActiveTexture(glState, true, cap(CaptureActiveTexture(replayState, true,
GL_TEXTURE0 + static_cast<GLenum>(stateActiveTexture))); GL_TEXTURE0 + static_cast<GLenum>(stateActiveTexture)));
} }
// Capture Renderbuffers. // Capture Renderbuffers.
const gl::RenderbufferManager &renderbuffers = glState.getRenderbufferManagerForCapture(); const gl::RenderbufferManager &renderbuffers = apiState.getRenderbufferManagerForCapture();
gl::RenderbufferID currentRenderbuffer = {0}; gl::RenderbufferID currentRenderbuffer = {0};
for (const auto &renderbufIter : renderbuffers) for (const auto &renderbufIter : renderbuffers)
...@@ -1114,9 +1191,9 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1114,9 +1191,9 @@ void CaptureMidExecutionSetup(const gl::Context *context,
const gl::Renderbuffer *renderbuffer = renderbufIter.second; const gl::Renderbuffer *renderbuffer = renderbufIter.second;
// Generate renderbuffer id. // Generate renderbuffer id.
cap(CaptureGenRenderbuffers(glState, true, 1, &id)); cap(CaptureGenRenderbuffers(replayState, true, 1, &id));
MaybeCaptureUpdateResourceIDs(setupCalls); MaybeCaptureUpdateResourceIDs(setupCalls);
cap(CaptureBindRenderbuffer(glState, true, GL_RENDERBUFFER, id)); cap(CaptureBindRenderbuffer(replayState, true, GL_RENDERBUFFER, id));
currentRenderbuffer = id; currentRenderbuffer = id;
...@@ -1126,12 +1203,12 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1126,12 +1203,12 @@ void CaptureMidExecutionSetup(const gl::Context *context,
{ {
// Note: We could also use extensions if available. // Note: We could also use extensions if available.
cap(CaptureRenderbufferStorageMultisample( cap(CaptureRenderbufferStorageMultisample(
glState, true, GL_RENDERBUFFER, renderbuffer->getSamples(), internalformat, replayState, true, GL_RENDERBUFFER, renderbuffer->getSamples(), internalformat,
renderbuffer->getWidth(), renderbuffer->getHeight())); renderbuffer->getWidth(), renderbuffer->getHeight()));
} }
else else
{ {
cap(CaptureRenderbufferStorage(glState, true, GL_RENDERBUFFER, internalformat, cap(CaptureRenderbufferStorage(replayState, true, GL_RENDERBUFFER, internalformat,
renderbuffer->getWidth(), renderbuffer->getHeight())); renderbuffer->getWidth(), renderbuffer->getHeight()));
} }
...@@ -1139,13 +1216,14 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1139,13 +1216,14 @@ void CaptureMidExecutionSetup(const gl::Context *context,
} }
// Set Renderbuffer binding. // Set Renderbuffer binding.
if (currentRenderbuffer != glState.getRenderbufferId()) if (currentRenderbuffer != apiState.getRenderbufferId())
{ {
cap(CaptureBindRenderbuffer(glState, true, GL_RENDERBUFFER, glState.getRenderbufferId())); cap(CaptureBindRenderbuffer(replayState, true, GL_RENDERBUFFER,
apiState.getRenderbufferId()));
} }
// Capture Framebuffers. // Capture Framebuffers.
const gl::FramebufferManager &framebuffers = glState.getFramebufferManagerForCapture(); const gl::FramebufferManager &framebuffers = apiState.getFramebufferManagerForCapture();
gl::FramebufferID currentDrawFramebuffer = {0}; gl::FramebufferID currentDrawFramebuffer = {0};
gl::FramebufferID currentReadFramebuffer = {0}; gl::FramebufferID currentReadFramebuffer = {0};
...@@ -1159,9 +1237,9 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1159,9 +1237,9 @@ void CaptureMidExecutionSetup(const gl::Context *context,
if (framebuffer->isDefault()) if (framebuffer->isDefault())
continue; continue;
cap(CaptureGenFramebuffers(glState, true, 1, &id)); cap(CaptureGenFramebuffers(replayState, true, 1, &id));
MaybeCaptureUpdateResourceIDs(setupCalls); MaybeCaptureUpdateResourceIDs(setupCalls);
cap(CaptureBindFramebuffer(glState, true, GL_FRAMEBUFFER, id)); cap(CaptureBindFramebuffer(replayState, true, GL_FRAMEBUFFER, id));
currentDrawFramebuffer = currentReadFramebuffer = id; currentDrawFramebuffer = currentReadFramebuffer = id;
// Color Attachments. // Color Attachments.
...@@ -1179,31 +1257,50 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1179,31 +1257,50 @@ void CaptureMidExecutionSetup(const gl::Context *context,
{ {
gl::ImageIndex index = colorAttachment.getTextureImageIndex(); gl::ImageIndex index = colorAttachment.getTextureImageIndex();
cap(CaptureFramebufferTexture2D(glState, true, GL_FRAMEBUFFER, cap(CaptureFramebufferTexture2D(replayState, true, GL_FRAMEBUFFER,
colorAttachment.getBinding(), index.getTarget(), colorAttachment.getBinding(), index.getTarget(),
{resourceID}, index.getLevelIndex())); {resourceID}, index.getLevelIndex()));
} }
else else
{ {
ASSERT(colorAttachment.type() == GL_RENDERBUFFER); ASSERT(colorAttachment.type() == GL_RENDERBUFFER);
cap(CaptureFramebufferRenderbuffer(glState, true, GL_FRAMEBUFFER, cap(CaptureFramebufferRenderbuffer(replayState, true, GL_FRAMEBUFFER,
colorAttachment.getBinding(), GL_RENDERBUFFER, colorAttachment.getBinding(), GL_RENDERBUFFER,
{resourceID})); {resourceID}));
} }
} }
const gl::FramebufferAttachment *depthAttachment = framebuffer->getDepthAttachment();
if (depthAttachment)
{
ASSERT(depthAttachment->type() == GL_RENDERBUFFER);
GLuint resourceID = depthAttachment->getResource()->getId();
cap(CaptureFramebufferRenderbuffer(replayState, true, GL_FRAMEBUFFER,
GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, {resourceID}));
}
const gl::FramebufferAttachment *stencilAttachment = framebuffer->getStencilAttachment();
if (stencilAttachment)
{
ASSERT(stencilAttachment->type() == GL_RENDERBUFFER);
GLuint resourceID = stencilAttachment->getResource()->getId();
cap(CaptureFramebufferRenderbuffer(replayState, true, GL_FRAMEBUFFER,
GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
{resourceID}));
}
// TODO(jmadill): Draw buffer states. http://anglebug.com/3662 // TODO(jmadill): Draw buffer states. http://anglebug.com/3662
} }
// Capture framebuffer bindings. // Capture framebuffer bindings.
gl::FramebufferID stateReadFramebuffer = glState.getReadFramebuffer()->id(); gl::FramebufferID stateReadFramebuffer = apiState.getReadFramebuffer()->id();
gl::FramebufferID stateDrawFramebuffer = glState.getDrawFramebuffer()->id(); gl::FramebufferID stateDrawFramebuffer = apiState.getDrawFramebuffer()->id();
if (stateDrawFramebuffer == stateReadFramebuffer) if (stateDrawFramebuffer == stateReadFramebuffer)
{ {
if (currentDrawFramebuffer != stateDrawFramebuffer || if (currentDrawFramebuffer != stateDrawFramebuffer ||
currentReadFramebuffer != stateReadFramebuffer) currentReadFramebuffer != stateReadFramebuffer)
{ {
cap(CaptureBindFramebuffer(glState, true, GL_FRAMEBUFFER, stateDrawFramebuffer)); cap(CaptureBindFramebuffer(replayState, true, GL_FRAMEBUFFER, stateDrawFramebuffer));
currentDrawFramebuffer = currentReadFramebuffer = stateDrawFramebuffer; currentDrawFramebuffer = currentReadFramebuffer = stateDrawFramebuffer;
} }
} }
...@@ -1211,21 +1308,22 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1211,21 +1308,22 @@ void CaptureMidExecutionSetup(const gl::Context *context,
{ {
if (currentDrawFramebuffer != stateDrawFramebuffer) if (currentDrawFramebuffer != stateDrawFramebuffer)
{ {
cap(CaptureBindFramebuffer(glState, true, GL_DRAW_FRAMEBUFFER, currentDrawFramebuffer)); cap(CaptureBindFramebuffer(replayState, true, GL_DRAW_FRAMEBUFFER,
currentDrawFramebuffer));
currentDrawFramebuffer = stateDrawFramebuffer; currentDrawFramebuffer = stateDrawFramebuffer;
} }
if (currentReadFramebuffer != stateReadFramebuffer) if (currentReadFramebuffer != stateReadFramebuffer)
{ {
cap(CaptureBindFramebuffer(glState, true, GL_READ_FRAMEBUFFER, cap(CaptureBindFramebuffer(replayState, true, GL_READ_FRAMEBUFFER,
glState.getReadFramebuffer()->id())); replayState.getReadFramebuffer()->id()));
currentReadFramebuffer = stateReadFramebuffer; currentReadFramebuffer = stateReadFramebuffer;
} }
} }
// Capture Shaders and Programs. // Capture Shaders and Programs.
const gl::ShaderProgramManager &shadersAndPrograms = const gl::ShaderProgramManager &shadersAndPrograms =
glState.getShaderProgramManagerForCapture(); apiState.getShaderProgramManagerForCapture();
const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaders = const gl::ResourceMap<gl::Shader, gl::ShaderProgramID> &shaders =
shadersAndPrograms.getShadersForCapture(); shadersAndPrograms.getShadersForCapture();
const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs = const gl::ResourceMap<gl::Program, gl::ShaderProgramID> &programs =
...@@ -1249,7 +1347,7 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1249,7 +1347,7 @@ void CaptureMidExecutionSetup(const gl::Context *context,
continue; continue;
} }
cap(CaptureCreateProgram(glState, true, id.value)); cap(CaptureCreateProgram(replayState, true, id.value));
// Compile with last linked sources. // Compile with last linked sources.
for (gl::ShaderType shaderType : program->getState().getLinkedShaderStages()) for (gl::ShaderType shaderType : program->getState().getLinkedShaderStages())
...@@ -1258,14 +1356,14 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1258,14 +1356,14 @@ void CaptureMidExecutionSetup(const gl::Context *context,
const char *sourcePointer = sourceString.c_str(); const char *sourcePointer = sourceString.c_str();
// Compile and attach the temporary shader. Then free it immediately. // Compile and attach the temporary shader. Then free it immediately.
cap(CaptureCreateShader(glState, true, shaderType, tempShaderID.value)); cap(CaptureCreateShader(replayState, true, shaderType, tempShaderID.value));
cap(CaptureShaderSource(glState, true, tempShaderID, 1, &sourcePointer, nullptr)); cap(CaptureShaderSource(replayState, true, tempShaderID, 1, &sourcePointer, nullptr));
cap(CaptureCompileShader(glState, true, tempShaderID)); cap(CaptureCompileShader(replayState, true, tempShaderID));
cap(CaptureAttachShader(glState, true, id, tempShaderID)); cap(CaptureAttachShader(replayState, true, id, tempShaderID));
cap(CaptureDeleteShader(glState, true, tempShaderID)); cap(CaptureDeleteShader(replayState, true, tempShaderID));
} }
cap(CaptureLinkProgram(glState, true, id)); cap(CaptureLinkProgram(replayState, true, id));
} }
// Handle shaders. // Handle shaders.
...@@ -1273,7 +1371,7 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1273,7 +1371,7 @@ void CaptureMidExecutionSetup(const gl::Context *context,
{ {
gl::ShaderProgramID id = {shaderIter.first}; gl::ShaderProgramID id = {shaderIter.first};
gl::Shader *shader = shaderIter.second; gl::Shader *shader = shaderIter.second;
cap(CaptureCreateShader(glState, true, shader->getType(), id.value)); cap(CaptureCreateShader(replayState, true, shader->getType(), id.value));
std::string shaderSource = shader->getSourceString(); std::string shaderSource = shader->getSourceString();
const char *sourcePointer = shaderSource.empty() ? nullptr : shaderSource.c_str(); const char *sourcePointer = shaderSource.empty() ? nullptr : shaderSource.c_str();
...@@ -1293,57 +1391,221 @@ void CaptureMidExecutionSetup(const gl::Context *context, ...@@ -1293,57 +1391,221 @@ void CaptureMidExecutionSetup(const gl::Context *context,
sourcePointer = capturedSource.c_str(); sourcePointer = capturedSource.c_str();
} }
cap(CaptureShaderSource(glState, true, id, 1, &sourcePointer, nullptr)); cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
cap(CaptureCompileShader(glState, true, id)); cap(CaptureCompileShader(replayState, true, id));
} }
if (sourcePointer && (!shader->isCompiled() || sourcePointer != shaderSource.c_str())) if (sourcePointer && (!shader->isCompiled() || sourcePointer != shaderSource.c_str()))
{ {
cap(CaptureShaderSource(glState, true, id, 1, &sourcePointer, nullptr)); cap(CaptureShaderSource(replayState, true, id, 1, &sourcePointer, nullptr));
} }
} }
// For now we assume the installed program executable is the same as the current program. // For now we assume the installed program executable is the same as the current program.
// TODO(jmadill): Handle installed program executable. http://anglebug.com/3662 // TODO(jmadill): Handle installed program executable. http://anglebug.com/3662
if (glState.getProgram()) if (apiState.getProgram())
{ {
cap(CaptureUseProgram(glState, true, glState.getProgram()->id())); cap(CaptureUseProgram(replayState, true, apiState.getProgram()->id()));
} }
// TODO(http://anglebug.com/3662): ES 3.x objects. // TODO(http://anglebug.com/3662): ES 3.x objects.
// Capture GL Context states. // Capture GL Context states.
// TODO(http://anglebug.com/3662): Complete state capture. // TODO(http://anglebug.com/3662): Complete state capture.
const gl::RasterizerState defaultRasterState; auto capCap = [cap, &replayState](GLenum capEnum, bool capValue) {
const gl::RasterizerState &currentRasterState = glState.getRasterizerState(); if (capValue)
if (currentRasterState.cullFace != defaultRasterState.cullFace)
{
if (currentRasterState.cullFace)
{ {
cap(CaptureEnable(glState, true, GL_CULL_FACE)); cap(CaptureEnable(replayState, true, capEnum));
} }
else else
{ {
cap(CaptureDisable(glState, true, GL_CULL_FACE)); cap(CaptureDisable(replayState, true, capEnum));
} }
};
// Rasterizer state. Missing ES 3.x features.
// TODO(http://anglebug.com/3662): Complete state capture.
const gl::RasterizerState &defaultRasterState = replayState.getRasterizerState();
const gl::RasterizerState &currentRasterState = apiState.getRasterizerState();
if (currentRasterState.cullFace != defaultRasterState.cullFace)
{
capCap(GL_CULL_FACE, currentRasterState.cullFace);
} }
if (currentRasterState.cullMode != defaultRasterState.cullMode) if (currentRasterState.cullMode != defaultRasterState.cullMode)
{ {
cap(CaptureCullFace(glState, true, currentRasterState.cullMode)); cap(CaptureCullFace(replayState, true, currentRasterState.cullMode));
} }
if (currentRasterState.frontFace != defaultRasterState.frontFace) if (currentRasterState.frontFace != defaultRasterState.frontFace)
{ {
cap(CaptureFrontFace(glState, true, currentRasterState.frontFace)); cap(CaptureFrontFace(replayState, true, currentRasterState.frontFace));
}
// Depth/stencil state.
const gl::DepthStencilState &defaultDSState = replayState.getDepthStencilState();
const gl::DepthStencilState &currentDSState = apiState.getDepthStencilState();
if (defaultDSState.depthFunc != currentDSState.depthFunc)
{
cap(CaptureDepthFunc(replayState, true, currentDSState.depthFunc));
}
if (defaultDSState.depthMask != currentDSState.depthMask)
{
cap(CaptureDepthMask(replayState, true, gl::ConvertToGLBoolean(currentDSState.depthMask)));
}
if (defaultDSState.depthTest != currentDSState.depthTest)
{
capCap(GL_DEPTH_TEST, currentDSState.depthTest);
}
if (defaultDSState.stencilTest != currentDSState.stencilTest)
{
capCap(GL_STENCIL_TEST, currentDSState.stencilTest);
}
if (defaultDSState.stencilFunc != currentDSState.stencilFunc ||
defaultDSState.stencilMask != currentDSState.stencilMask || apiState.getStencilRef() != 0)
{
cap(CaptureStencilFuncSeparate(replayState, true, GL_FRONT, currentDSState.stencilFunc,
apiState.getStencilRef(), currentDSState.stencilMask));
}
if (defaultDSState.stencilBackFunc != currentDSState.stencilBackFunc ||
defaultDSState.stencilBackMask != currentDSState.stencilBackMask ||
apiState.getStencilBackRef() != 0)
{
cap(CaptureStencilFuncSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFunc,
apiState.getStencilBackRef(),
currentDSState.stencilBackMask));
}
if (defaultDSState.stencilFail != currentDSState.stencilFail ||
defaultDSState.stencilPassDepthFail != currentDSState.stencilPassDepthFail ||
defaultDSState.stencilPassDepthPass != currentDSState.stencilPassDepthPass)
{
cap(CaptureStencilOpSeparate(replayState, true, GL_FRONT, currentDSState.stencilFail,
currentDSState.stencilPassDepthFail,
currentDSState.stencilPassDepthPass));
}
if (defaultDSState.stencilBackFail != currentDSState.stencilBackFail ||
defaultDSState.stencilBackPassDepthFail != currentDSState.stencilBackPassDepthFail ||
defaultDSState.stencilBackPassDepthPass != currentDSState.stencilBackPassDepthPass)
{
cap(CaptureStencilOpSeparate(replayState, true, GL_BACK, currentDSState.stencilBackFail,
currentDSState.stencilBackPassDepthFail,
currentDSState.stencilBackPassDepthPass));
}
if (defaultDSState.stencilWritemask != currentDSState.stencilWritemask)
{
cap(CaptureStencilMaskSeparate(replayState, true, GL_FRONT,
currentDSState.stencilWritemask));
}
if (defaultDSState.stencilBackWritemask != currentDSState.stencilBackWritemask)
{
cap(CaptureStencilMaskSeparate(replayState, true, GL_BACK,
currentDSState.stencilBackWritemask));
}
// Blend state.
const gl::BlendState &defaultBlendState = replayState.getBlendState();
const gl::BlendState &currentBlendState = apiState.getBlendState();
if (currentBlendState.blend != defaultBlendState.blend)
{
capCap(GL_BLEND, currentBlendState.blend);
}
if (currentBlendState.sourceBlendRGB != defaultBlendState.sourceBlendRGB ||
currentBlendState.destBlendRGB != defaultBlendState.destBlendRGB ||
currentBlendState.sourceBlendAlpha != defaultBlendState.sourceBlendAlpha ||
currentBlendState.destBlendAlpha != defaultBlendState.destBlendAlpha)
{
cap(CaptureBlendFuncSeparate(
replayState, true, currentBlendState.sourceBlendRGB, currentBlendState.destBlendRGB,
currentBlendState.sourceBlendAlpha, currentBlendState.destBlendAlpha));
}
if (currentBlendState.blendEquationRGB != defaultBlendState.blendEquationRGB ||
currentBlendState.blendEquationAlpha != defaultBlendState.blendEquationAlpha)
{
cap(CaptureBlendEquationSeparate(replayState, true, currentBlendState.blendEquationRGB,
currentBlendState.blendEquationAlpha));
}
if (currentBlendState.colorMaskRed != defaultBlendState.colorMaskRed ||
currentBlendState.colorMaskGreen != defaultBlendState.colorMaskGreen ||
currentBlendState.colorMaskBlue != defaultBlendState.colorMaskBlue ||
currentBlendState.colorMaskAlpha != defaultBlendState.colorMaskAlpha)
{
cap(CaptureColorMask(replayState, true,
gl::ConvertToGLBoolean(currentBlendState.colorMaskRed),
gl::ConvertToGLBoolean(currentBlendState.colorMaskGreen),
gl::ConvertToGLBoolean(currentBlendState.colorMaskBlue),
gl::ConvertToGLBoolean(currentBlendState.colorMaskAlpha)));
}
const gl::ColorF &currentBlendColor = apiState.getBlendColor();
if (currentBlendColor != gl::ColorF())
{
cap(CaptureBlendColor(replayState, true, currentBlendColor.red, currentBlendColor.green,
currentBlendColor.blue, currentBlendColor.alpha));
}
// Pixel storage states.
// TODO(jmadill): ES 3.x+ implementation. http://anglebug.com/3662
if (currentPackState.alignment != apiState.getPackAlignment())
{
cap(CapturePixelStorei(replayState, true, GL_UNPACK_ALIGNMENT,
apiState.getPackAlignment()));
currentPackState.alignment = apiState.getPackAlignment();
} }
const gl::ColorF &currentClearColor = glState.getColorClearValue(); // Clear state. Missing ES 3.x features.
// TODO(http://anglebug.com/3662): Complete state capture.
const gl::ColorF &currentClearColor = apiState.getColorClearValue();
if (currentClearColor != gl::ColorF()) if (currentClearColor != gl::ColorF())
{ {
cap(CaptureClearColor(glState, true, currentClearColor.red, currentClearColor.green, cap(CaptureClearColor(replayState, true, currentClearColor.red, currentClearColor.green,
currentClearColor.blue, currentClearColor.alpha)); currentClearColor.blue, currentClearColor.alpha));
} }
if (apiState.getDepthClearValue() != 1.0f)
{
cap(CaptureClearDepthf(replayState, true, apiState.getDepthClearValue()));
}
// Viewport / scissor / clipping planes.
const gl::Rectangle &currentViewport = apiState.getViewport();
if (currentViewport != gl::Rectangle())
{
cap(CaptureViewport(replayState, true, currentViewport.x, currentViewport.y,
currentViewport.width, currentViewport.height));
}
if (apiState.getNearPlane() != 0.0f || apiState.getFarPlane() != 1.0f)
{
cap(CaptureDepthRangef(replayState, true, apiState.getNearPlane(), apiState.getFarPlane()));
}
if (apiState.isScissorTestEnabled())
{
capCap(GL_SCISSOR_TEST, apiState.isScissorTestEnabled());
}
const gl::Rectangle &currentScissor = apiState.getScissor();
if (currentScissor != gl::Rectangle())
{
cap(CaptureScissor(replayState, true, currentScissor.x, currentScissor.y,
currentScissor.width, currentScissor.height));
}
// Allow the replayState object to be destroyed conveniently.
replayState.setBufferBinding(context, gl::BufferBinding::Array, nullptr);
} }
} // namespace } // namespace
......
...@@ -356,6 +356,8 @@ class State : angle::NonCopyable ...@@ -356,6 +356,8 @@ class State : angle::NonCopyable
} }
} }
ANGLE_INLINE Buffer *getArrayBuffer() const { return getTargetBuffer(BufferBinding::Array); }
angle::Result setIndexedBufferBinding(const Context *context, angle::Result setIndexedBufferBinding(const Context *context,
BufferBinding target, BufferBinding target,
GLuint index, GLuint index,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment