static void dumpViewports(StateWriter &writer, ID3D10Device *pDevice) { D3D10_VIEWPORT vps[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; UINT numViewports = 0, i; pDevice->RSGetViewports(&numViewports, NULL); pDevice->RSGetViewports(&numViewports, vps); writer.beginMember("Viewports"); writer.beginArray(); for (i = 0; i < numViewports; ++i) { dumpStateObject(writer, vps[i]); } writer.endArray(); writer.endMember(); }
static void dumpScissors(StateWriter &writer, ID3D10Device *pDevice) { D3D10_RECT rects[D3D10_VIEWPORT_AND_SCISSORRECT_OBJECT_COUNT_PER_PIPELINE]; UINT numRects = 0, i; pDevice->RSGetScissorRects(&numRects, NULL); pDevice->RSGetScissorRects(&numRects, rects); writer.beginMember("Scissors"); writer.beginArray(); for (i = 0; i < numRects; ++i) { dumpStateObject(writer, rects[i]); } writer.endArray(); writer.endMember(); }
static void dumpAttribArray(StateWriter &writer, const std::string & name, const AttribDesc &desc, const GLbyte *data) { writer.beginMember(name); if (desc.size > 1) { writer.beginArray(); } for (GLint i = 0; i < desc.size; ++i) { const GLbyte *row = data + desc.arrayStride*i; dumpAttrib(writer, desc, row); } if (desc.size > 1) { writer.endArray(); } writer.endMember(); }
static void dumpBlendState(StateWriter &writer, ID3D10Device *pDevice) { com_ptr<ID3D10BlendState> pBlendState; FLOAT BlendFactor[4]; UINT SampleMask; pDevice->OMGetBlendState(&pBlendState, BlendFactor, &SampleMask); writer.beginMember("BlendState"); dumpStateObjectDesc(writer, pBlendState); writer.endMember(); // BlendState writer.beginMember("BlendFactor"); writer.beginArray(); writer.writeFloat(BlendFactor[0]); writer.writeFloat(BlendFactor[1]); writer.writeFloat(BlendFactor[2]); writer.writeFloat(BlendFactor[3]); writer.endArray(); writer.endMember(); // BlendFactor writer.writeIntMember("SampleMask", SampleMask); }
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 dumpArbProgramUniforms(StateWriter &writer, Context &context, GLenum target, const char *prefix) { if (context.ES || context.core || !glIsEnabled(target)) { return; } GLint program_parameters = 0; glGetProgramivARB(target, GL_PROGRAM_PARAMETERS_ARB, &program_parameters); if (!program_parameters) { return; } GLint max_program_local_parameters = 0; glGetProgramivARB(target, GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, &max_program_local_parameters); for (GLint index = 0; index < max_program_local_parameters; ++index) { GLdouble params[4] = {0, 0, 0, 0}; glGetProgramLocalParameterdvARB(target, index, params); if (!params[0] && !params[1] && !params[2] && !params[3]) { continue; } char name[256]; snprintf(name, sizeof name, "%sprogram.local[%i]", prefix, index); writer.beginMember(name); writer.beginArray(); writer.writeFloat(params[0]); writer.writeFloat(params[1]); writer.writeFloat(params[2]); writer.writeFloat(params[3]); writer.endArray(); writer.endMember(); } GLint max_program_env_parameters = 0; glGetProgramivARB(target, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, &max_program_env_parameters); for (GLint index = 0; index < max_program_env_parameters; ++index) { GLdouble params[4] = {0, 0, 0, 0}; glGetProgramEnvParameterdvARB(target, index, params); if (!params[0] && !params[1] && !params[2] && !params[3]) { continue; } char name[256]; snprintf(name, sizeof name, "%sprogram.env[%i]", prefix, index); writer.beginMember(name); writer.beginArray(); writer.writeFloat(params[0]); writer.writeFloat(params[1]); writer.writeFloat(params[2]); writer.writeFloat(params[3]); 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(); }
static void dumpUniform(StateWriter &writer, GLint program, const AttribDesc & desc, const GLchar *name) { if (desc.elemType == GL_NONE) { return; } union { GLfloat fvalues[4*4]; GLdouble dvalues[4*4]; GLint ivalues[4*4]; GLuint uivalues[4*4]; GLint64 i64values[4*4]; GLuint64 ui64values[4*4]; GLbyte data[4*4*4]; } u; GLint i; std::string qualifiedName = resolveUniformName(name, desc.size); writer.beginMember(qualifiedName); if (desc.size > 1) { writer.beginArray(); } for (i = 0; i < desc.size; ++i) { std::stringstream ss; ss << qualifiedName; if (desc.size > 1) { ss << '[' << i << ']'; } std::string elemName = ss.str(); GLint location = glGetUniformLocation(program, elemName.c_str()); assert(location != -1); if (location == -1) { continue; } switch (desc.elemType) { case GL_FLOAT: glGetUniformfv(program, location, u.fvalues); break; case GL_DOUBLE: glGetUniformdv(program, location, u.dvalues); break; case GL_INT: glGetUniformiv(program, location, u.ivalues); break; case GL_UNSIGNED_INT: glGetUniformuiv(program, location, u.uivalues); break; case GL_INT64_ARB: glGetUniformi64vARB(program, location, u.i64values); break; case GL_UNSIGNED_INT64_ARB: glGetUniformui64vARB(program, location, u.ui64values); break; case GL_BOOL: glGetUniformiv(program, location, u.ivalues); break; default: assert(0); break; } dumpAttrib(writer, desc, u.data); } if (desc.size > 1) { writer.endArray(); } writer.endMember(); }
static void dumpAttrib(StateWriter &writer, const AttribDesc &desc, const GLbyte *data) { assert(desc); if (desc.numRows > 1) { writer.beginArray(); } for (GLint row = 0; row < desc.numRows; ++row) { if (desc.numCols > 1) { writer.beginArray(); } for (GLint col = 0; col < desc.numCols; ++col) { union { const GLbyte *rawvalue; const GLfloat *fvalue; const GLdouble *dvalue; const GLint *ivalue; const GLuint *uivalue; const GLint64 *i64value; const GLuint64 *ui64value; } u; u.rawvalue = data + row*desc.rowStride + col*desc.colStride; switch (desc.elemType) { case GL_FLOAT: writer.writeFloat(*u.fvalue); break; case GL_DOUBLE: writer.writeFloat(*u.dvalue); break; case GL_INT: writer.writeInt(*u.ivalue); break; case GL_UNSIGNED_INT: writer.writeInt(*u.uivalue); break; case GL_INT64_ARB: writer.writeInt(*u.i64value); break; case GL_UNSIGNED_INT64_ARB: writer.writeInt(*u.ui64value); break; case GL_BOOL: writer.writeBool(*u.uivalue); break; default: assert(0); writer.writeNull(); break; } } if (desc.numCols > 1) { writer.endArray(); } } if (desc.numRows > 1) { writer.endArray(); } }