static void dumpShaders(StateWriter &writer, ID3D10Device *pDevice) { writer.beginMember("shaders"); writer.beginObject(); com_ptr<ID3D10VertexShader> pVertexShader; pDevice->VSGetShader(&pVertexShader); if (pVertexShader) { dumpShader<ID3D10DeviceChild>(writer, "VS", pVertexShader); } com_ptr<ID3D10GeometryShader> pGeometryShader; pDevice->GSGetShader(&pGeometryShader); if (pGeometryShader) { dumpShader<ID3D10DeviceChild>(writer, "GS", pGeometryShader); } com_ptr<ID3D10PixelShader> pPixelShader; pDevice->PSGetShader(&pPixelShader); if (pPixelShader) { dumpShader<ID3D10DeviceChild>(writer, "PS", pPixelShader); } writer.endObject(); writer.endMember(); // shaders }
static void dumpProgramUniformsStage(StateWriter &writer, GLint program, const char *stage) { if (program <= 0) { return; } writer.beginMember(stage); writer.beginObject(); dumpProgramUniforms(writer, program); writer.endObject(); writer.endMember(); }
static void dumpParameters(StateWriter &writer, ID3D10Device *pDevice) { // TODO: dump description of current bound state writer.beginMember("parameters"); writer.beginObject(); dumpRasterizerState(writer, pDevice); dumpBlendState(writer, pDevice); dumpDepthStencilState(writer, pDevice); dumpViewports(writer, pDevice); dumpScissors(writer, pDevice); writer.endObject(); writer.endMember(); // parameters }
void dumpTextures(StateWriter &writer, IDirect3DDevice8 *pDevice) { HRESULT hr; writer.beginMember("textures"); writer.beginObject(); for (DWORD Stage = 0; Stage < 8; ++Stage) { com_ptr<IDirect3DBaseTexture8> pTexture; hr = pDevice->GetTexture(Stage, &pTexture); if (FAILED(hr)) { continue; } if (!pTexture) { continue; } D3DRESOURCETYPE Type = pTexture->GetType(); DWORD NumFaces = Type == D3DRTYPE_CUBETEXTURE ? 6 : 1; DWORD NumLevels = pTexture->GetLevelCount(); for (DWORD Face = 0; Face < NumFaces; ++Face) { for (DWORD Level = 0; Level < NumLevels; ++Level) { image::Image *image; image = getTextureImage(pDevice, pTexture, static_cast<D3DCUBEMAP_FACES>(Face), Level); if (image) { char label[128]; if (Type == D3DRTYPE_CUBETEXTURE) { _snprintf(label, sizeof label, "PS_RESOURCE_%lu_FACE_%lu_LEVEL_%lu", Stage, Face, Level); } else { _snprintf(label, sizeof label, "PS_RESOURCE_%lu_LEVEL_%lu", Stage, Level); } writer.beginMember(label); writer.writeImage(image); writer.endMember(); // PS_RESOURCE_* delete image; } } } } writer.endObject(); writer.endMember(); // textures }
void dumpFramebuffer(StateWriter &writer, ID3D10Device *pDevice) { writer.beginMember("framebuffer"); writer.beginObject(); ID3D10RenderTargetView *pRenderTargetViews[D3D10_SIMULTANEOUS_RENDER_TARGET_COUNT]; ID3D10DepthStencilView *pDepthStencilView; pDevice->OMGetRenderTargets(ARRAYSIZE(pRenderTargetViews), pRenderTargetViews, &pDepthStencilView); for (UINT i = 0; i < ARRAYSIZE(pRenderTargetViews); ++i) { if (!pRenderTargetViews[i]) { continue; } image::Image *image; image = getRenderTargetViewImage(pDevice, pRenderTargetViews[i]); if (image) { char label[64]; _snprintf(label, sizeof label, "RENDER_TARGET_%u", i); writer.beginMember(label); writer.writeImage(image); writer.endMember(); // RENDER_TARGET_* delete image; } pRenderTargetViews[i]->Release(); } if (pDepthStencilView) { image::Image *image; image = getDepthStencilViewImage(pDevice, pDepthStencilView); if (image) { writer.beginMember("DEPTH_STENCIL"); writer.writeImage(image); writer.endMember(); delete image; } pDepthStencilView->Release(); } writer.endObject(); writer.endMember(); // framebuffer }
void dumpTextures(StateWriter &writer, ID3D10Device *pDevice) { writer.beginMember("textures"); writer.beginObject(); ID3D10ShaderResourceView *pShaderResourceViews[D3D10_COMMONSHADER_SAMPLER_SLOT_COUNT]; pDevice->PSGetShaderResources(0, ARRAYSIZE(pShaderResourceViews), pShaderResourceViews); dumpStageTextures(writer, pDevice, "PS", ARRAYSIZE(pShaderResourceViews), pShaderResourceViews); pDevice->VSGetShaderResources(0, ARRAYSIZE(pShaderResourceViews), pShaderResourceViews); dumpStageTextures(writer, pDevice, "VS", ARRAYSIZE(pShaderResourceViews), pShaderResourceViews); pDevice->GSGetShaderResources(0, ARRAYSIZE(pShaderResourceViews), pShaderResourceViews); dumpStageTextures(writer, pDevice, "GS", ARRAYSIZE(pShaderResourceViews), pShaderResourceViews); writer.endObject(); writer.endMember(); // textures }
void dumpFramebuffer(StateWriter &writer, IDirect3DDevice8 *pDevice) { HRESULT hr; writer.beginMember("framebuffer"); writer.beginObject(); com_ptr<IDirect3DSurface8> pRenderTarget; hr = pDevice->GetRenderTarget(&pRenderTarget); if (SUCCEEDED(hr) && pRenderTarget) { image::Image *image; image = getRenderTargetImage(pDevice, pRenderTarget); if (image) { writer.beginMember("RENDER_TARGET_0"); writer.writeImage(image); writer.endMember(); // RENDER_TARGET_* delete image; } } com_ptr<IDirect3DSurface8> pDepthStencil; hr = pDevice->GetDepthStencilSurface(&pDepthStencil); if (SUCCEEDED(hr) && pDepthStencil) { image::Image *image; image = getSurfaceImage(pDevice, pDepthStencil); if (image) { writer.beginMember("DEPTH_STENCIL"); writer.writeImage(image); writer.endMember(); // RENDER_TARGET_* delete image; } } writer.endObject(); writer.endMember(); // framebuffer }
void dumpShadersUniforms(StateWriter &writer, Context &context) { GLint pipeline = 0; GLint vertex_program = 0; GLint fragment_program = 0; GLint geometry_program = 0; GLint tess_control_program = 0; GLint tess_evaluation_program = 0; GLint compute_program = 0; if (!context.ES) { glGetIntegerv(GL_PROGRAM_PIPELINE_BINDING, &pipeline); if (pipeline) { glGetProgramPipelineiv(pipeline, GL_VERTEX_SHADER, &vertex_program); glGetProgramPipelineiv(pipeline, GL_FRAGMENT_SHADER, &fragment_program); glGetProgramPipelineiv(pipeline, GL_GEOMETRY_SHADER, &geometry_program); glGetProgramPipelineiv(pipeline, GL_TESS_CONTROL_SHADER, &tess_control_program); glGetProgramPipelineiv(pipeline, GL_TESS_EVALUATION_SHADER, &tess_evaluation_program); glGetProgramPipelineiv(pipeline, GL_COMPUTE_SHADER, &compute_program); } } GLint program = 0; if (!pipeline) { glGetIntegerv(GL_CURRENT_PROGRAM, &program); } writer.beginMember("shaders"); writer.beginObject(); if (pipeline) { dumpProgram(writer, context, vertex_program); dumpProgram(writer, context, fragment_program); dumpProgram(writer, context, geometry_program); dumpProgram(writer, context, tess_control_program); dumpProgram(writer, context, tess_evaluation_program); dumpProgram(writer, context, compute_program); } else if (program) { dumpProgram(writer, context, program); } else { dumpArbProgram(writer, context, GL_FRAGMENT_PROGRAM_ARB); dumpArbProgram(writer, context, GL_VERTEX_PROGRAM_ARB); } writer.endObject(); writer.endMember(); // shaders writer.beginMember("uniforms"); writer.beginObject(); if (pipeline) { dumpProgramUniformsStage(writer, vertex_program, "GL_VERTEX_SHADER"); dumpProgramUniformsStage(writer, fragment_program, "GL_FRAGMENT_SHADER"); dumpProgramUniformsStage(writer, geometry_program, "GL_GEOMETRY_SHADER"); dumpProgramUniformsStage(writer, tess_control_program, "GL_TESS_CONTROL_SHADER"); dumpProgramUniformsStage(writer, tess_evaluation_program, "GL_TESS_EVALUATION_SHADER"); dumpProgramUniformsStage(writer, compute_program, "GL_COMPUTE_SHADER"); } else if (program) { dumpProgramUniforms(writer, program); } else { dumpArbProgramUniforms(writer, context, GL_FRAGMENT_PROGRAM_ARB, "fp."); dumpArbProgramUniforms(writer, context, GL_VERTEX_PROGRAM_ARB, "vp."); } writer.endObject(); writer.endMember(); // uniforms writer.beginMember("buffers"); writer.beginObject(); if (!context.ES) { if (pipeline) { dumpVertexAttributes(writer, context, vertex_program); } else { dumpVertexAttributes(writer, context, program); } if (program) { dumpTransformFeedback(writer, program); } } writer.endObject(); writer.endMember(); // buffers }
static void dumpVertexAttributes(StateWriter &writer, Context &context, GLint program) { if (program <= 0) { return; } GLint activeAttribs = 0; glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttribs); if (!activeAttribs) { return; } GLint max_name_length = 0; glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_name_length); std::vector<GLchar> name(max_name_length); std::map<GLuint, BufferMapping> mappings; std::vector<VertexAttrib> attribs; unsigned count = ~0U; for (GLint index = 0; index < activeAttribs; ++index) { GLsizei length = 0; GLint shaderSize = 0; GLenum shaderType = GL_NONE; glGetActiveAttrib(program, index, max_name_length, &length, &shaderSize, &shaderType, &name[0]); if (isBuiltinName(&name[0])) { // TODO: Handle built-ins too std::cerr << "warning: dumping of built-in vertex attribute (" << &name[0] << ") not yet supported\n"; continue; } GLint location = glGetAttribLocation(program, &name[0]); if (location < 0) { continue; } GLint buffer = 0; glGetVertexAttribiv(location, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &buffer); if (!buffer) { continue; } GLint size = 0; glGetVertexAttribiv(location, GL_VERTEX_ATTRIB_ARRAY_SIZE, &size); GLint type = 0; glGetVertexAttribiv(location, GL_VERTEX_ATTRIB_ARRAY_TYPE, &type); GLint normalized = 0; glGetVertexAttribiv(location, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &normalized); GLint stride = 0; glGetVertexAttribiv(location, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &stride); GLvoid * pointer = 0; glGetVertexAttribPointerv(location, GL_VERTEX_ATTRIB_ARRAY_POINTER, &pointer); GLint offset = reinterpret_cast<intptr_t>(pointer); assert(offset >= 0); GLint divisor = 0; glGetVertexAttribiv(location, GL_VERTEX_ATTRIB_ARRAY_DIVISOR, &divisor); if (divisor) { // TODO: not clear the best way of presenting instanced attibutes on the dump std::cerr << "warning: dumping of instanced attributes (" << &name[0] << ") not yet supported\n"; return; } if (size == GL_BGRA) { std::cerr << "warning: dumping of GL_BGRA attributes (" << &name[0] << ") not yet supported\n"; size = 4; } AttribDesc desc(type, size); if (!desc) { std::cerr << "warning: dumping of packed attribute (" << &name[0] << ") not yet supported\n"; // TODO: handle continue; } attribs.emplace_back(); VertexAttrib &attrib = attribs.back(); attrib.name = &name[0]; // TODO handle normalized attributes if (normalized) { std::cerr << "warning: dumping of normalized attribute (" << &name[0] << ") not yet supported\n"; } attrib.desc = desc; GLsizei attribSize = attrib.desc.arrayStride; if (stride == 0) { // tightly packed stride = attribSize; } attrib.offset = offset; attrib.stride = stride; BufferMapping &mapping = mappings[buffer]; attrib.map = (const GLbyte *)mapping.map(GL_ARRAY_BUFFER, buffer); BufferBinding bb(GL_ARRAY_BUFFER, buffer); GLint bufferSize = 0; glGetBufferParameteriv(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, &bufferSize); if (bufferSize <= offset || bufferSize <= offset + attribSize) { return; } else { unsigned attribCount = (bufferSize - offset - attribSize)/stride + 1; count = std::min(count, attribCount); } } if (count == 0 || count == ~0U || attribs.empty()) { return; } writer.beginMember("vertices"); writer.beginArray(); for (unsigned vertex = 0; vertex < count; ++vertex) { writer.beginObject(); for (auto attrib : attribs) { const AttribDesc & desc = attrib.desc; assert(desc); const GLbyte *vertex_data = attrib.map + attrib.stride*vertex + attrib.offset; dumpAttribArray(writer, attrib.name, desc, vertex_data); } writer.endObject(); } writer.endArray(); writer.endMember(); }
static inline void dumpTransformFeedback(StateWriter &writer, GLint program) { GLint transform_feedback_varyings = 0; glGetProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYINGS, &transform_feedback_varyings); if (!transform_feedback_varyings) { return; } GLint max_name_length = 0; glGetProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &max_name_length); std::vector<GLchar> name(max_name_length); GLint buffer_mode = GL_INTERLEAVED_ATTRIBS; glGetProgramiv(program, GL_TRANSFORM_FEEDBACK_BUFFER_MODE, &buffer_mode); std::vector<TransformFeedbackAttrib> attribs(transform_feedback_varyings); // Calculate the offsets and strides of each attribute according to // the value of GL_TRANSFORM_FEEDBACK_BUFFER_MODE GLsizei cum_attrib_offset = 0; for (GLint slot = 0; slot < transform_feedback_varyings; ++slot) { TransformFeedbackAttrib & attrib = attribs[slot]; GLsizei length = 0; GLsizei size = 0; GLenum type = GL_NONE; glGetTransformFeedbackVarying(program, slot, max_name_length, &length, &size, &type, &name[0]); attrib.name = &name[0]; const AttribDesc & desc = attrib.desc = AttribDesc(type, size); if (!desc) { return; } attrib.size = desc.arrayStride; switch (buffer_mode) { case GL_INTERLEAVED_ATTRIBS: attrib.offset = cum_attrib_offset; break; case GL_SEPARATE_ATTRIBS: attrib.offset = 0; attrib.stride = desc.arrayStride; break; default: assert(0); attrib.offset = 0; attrib.stride = 0; } cum_attrib_offset += desc.arrayStride; } if (buffer_mode == GL_INTERLEAVED_ATTRIBS) { for (GLint slot = 0; slot < transform_feedback_varyings; ++slot) { TransformFeedbackAttrib & attrib = attribs[slot]; attrib.stride = cum_attrib_offset; } } GLint previous_tbo = 0; glGetIntegerv(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, &previous_tbo); // Map the buffers and calculate how many vertices can they hold // XXX: We currently limit to 1024, or things can get significantly slow. unsigned numVertices = 16*1024; for (GLint slot = 0; slot < transform_feedback_varyings; ++slot) { TransformFeedbackAttrib & attrib = attribs[slot]; attrib.map = NULL; if (slot == 0 || buffer_mode != GL_INTERLEAVED_ATTRIBS) { GLint tbo = 0; glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_BINDING, slot, &tbo); if (!tbo) { numVertices = 0; continue; } GLint start = 0; glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_START, slot, &start); GLint size = 0; glGetIntegeri_v(GL_TRANSFORM_FEEDBACK_BUFFER_SIZE, slot, &size); glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, tbo); if (size == 0) { glGetBufferParameteriv(GL_TRANSFORM_FEEDBACK_BUFFER, GL_BUFFER_SIZE, &size); assert(size >= start); size -= start; } unsigned numAttribVertices = calcNumElements(size, attrib.offset, attrib.size, attrib.stride); numVertices = std::min(numVertices, numAttribVertices); attrib.map = (const GLbyte *)attrib.mapping.map(GL_TRANSFORM_FEEDBACK_BUFFER, tbo) + start; } else { attrib.map = attribs[0].map; } } glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, previous_tbo); // Actually dump the vertices writer.beginMember("GL_TRANSFORM_FEEDBACK"); writer.beginArray(); for (unsigned vertex = 0; vertex < numVertices; ++vertex) { writer.beginObject(); for (GLint slot = 0; slot < transform_feedback_varyings; ++slot) { TransformFeedbackAttrib & attrib = attribs[slot]; if (!attrib.map) { continue; } const AttribDesc & desc = attrib.desc; assert(desc); const GLbyte *vertex_data = attrib.map + attrib.stride*vertex + attrib.offset; dumpAttribArray(writer, attrib.name, desc, vertex_data); } writer.endObject(); } writer.endArray(); writer.endMember(); }