void DoSerialise(SerialiserType &ser, DynamicDescriptorCopy &el) { D3D12ResourceManager *rm = (D3D12ResourceManager *)ser.GetUserData(); SERIALISE_MEMBER(type); PortableHandle dst, src; if(ser.IsWriting()) { dst = ToPortableHandle(el.dst); src = ToPortableHandle(el.src); } ser.Serialise("dst", dst); ser.Serialise("src", src); if(ser.IsReading()) { if(rm) { el.dst = DescriptorFromPortableHandle(rm, dst); el.src = DescriptorFromPortableHandle(rm, src); } else { el.dst = NULL; el.src = NULL; } } }
void DoSerialise(SerialiserType &ser, D3D12_RANGE &el) { // serialise as uint64, so we're 32-bit/64-bit compatible uint64_t Begin = el.Begin; uint64_t End = el.End; ser.Serialise("Begin", Begin); ser.Serialise("End", End); if(ser.IsReading()) { el.Begin = (SIZE_T)Begin; el.End = (SIZE_T)End; } }
void DoSerialise(SerialiserType &ser, D3D12_CACHED_PIPELINE_STATE &el) { // don't serialise these, just set to NULL/0. See the definition of SERIALISE_MEMBER_DUMMY SERIALISE_MEMBER_ARRAY_EMPTY(pCachedBlob); uint64_t CachedBlobSizeInBytes = 0; ser.Serialise("CachedBlobSizeInBytes", CachedBlobSizeInBytes); }
void DoSerialise(SerialiserType &ser, D3D12_SHADER_BYTECODE &el) { // don't serialise size_t, otherwise capture/replay between different bit-ness won't work { uint64_t BytecodeLength = el.BytecodeLength; ser.Serialise("BytecodeLength", BytecodeLength); if(ser.IsReading()) el.BytecodeLength = (size_t)BytecodeLength; } SERIALISE_MEMBER_ARRAY(pShaderBytecode, BytecodeLength); }
void DoSerialise(SerialiserType &ser, D3D12BufferLocation &el) { D3D12ResourceManager *rm = (D3D12ResourceManager *)ser.GetUserData(); ResourceId buffer; UINT64 offs = 0; if(ser.IsWriting()) WrappedID3D12Resource::GetResIDFromAddr(el.Location, buffer, offs); ser.Serialise("Buffer", buffer); ser.Serialise("Offset", offs); if(ser.IsReading()) { if(rm && buffer != ResourceId() && rm->HasLiveResource(buffer)) el.Location = rm->GetLiveAs<ID3D12Resource>(buffer)->GetGPUVirtualAddress() + offs; else el.Location = 0; } }
void DoSerialise(SerialiserType &ser, ProgramUniformValue &el) { SERIALISE_MEMBER(Type); SERIALISE_MEMBER(Location); // some special logic here, we decode Type to figure out what the actual data is, and serialise it // with the right type. VarType baseType = VarType::Float; uint32_t elemCount = 1; switch(el.Type) { case eGL_FLOAT_MAT4: case eGL_FLOAT_MAT4x3: case eGL_FLOAT_MAT4x2: case eGL_FLOAT_MAT3: case eGL_FLOAT_MAT3x4: case eGL_FLOAT_MAT3x2: case eGL_FLOAT_MAT2: case eGL_FLOAT_MAT2x4: case eGL_FLOAT_MAT2x3: case eGL_FLOAT: case eGL_FLOAT_VEC2: case eGL_FLOAT_VEC3: case eGL_FLOAT_VEC4: baseType = VarType::Float; break; case eGL_DOUBLE_MAT4: case eGL_DOUBLE_MAT4x3: case eGL_DOUBLE_MAT4x2: case eGL_DOUBLE_MAT3: case eGL_DOUBLE_MAT3x4: case eGL_DOUBLE_MAT3x2: case eGL_DOUBLE_MAT2: case eGL_DOUBLE_MAT2x4: case eGL_DOUBLE_MAT2x3: case eGL_DOUBLE: case eGL_DOUBLE_VEC2: case eGL_DOUBLE_VEC3: case eGL_DOUBLE_VEC4: baseType = VarType::Double; break; case eGL_SAMPLER_1D: case eGL_SAMPLER_2D: case eGL_SAMPLER_3D: case eGL_SAMPLER_CUBE: case eGL_SAMPLER_CUBE_MAP_ARRAY: case eGL_SAMPLER_1D_SHADOW: case eGL_SAMPLER_2D_SHADOW: case eGL_SAMPLER_1D_ARRAY: case eGL_SAMPLER_2D_ARRAY: case eGL_SAMPLER_1D_ARRAY_SHADOW: case eGL_SAMPLER_2D_ARRAY_SHADOW: case eGL_SAMPLER_2D_MULTISAMPLE: case eGL_SAMPLER_2D_MULTISAMPLE_ARRAY: case eGL_SAMPLER_CUBE_SHADOW: case eGL_SAMPLER_CUBE_MAP_ARRAY_SHADOW: case eGL_SAMPLER_BUFFER: case eGL_SAMPLER_2D_RECT: case eGL_SAMPLER_2D_RECT_SHADOW: case eGL_INT_SAMPLER_1D: case eGL_INT_SAMPLER_2D: case eGL_INT_SAMPLER_3D: case eGL_INT_SAMPLER_CUBE: case eGL_INT_SAMPLER_CUBE_MAP_ARRAY: case eGL_INT_SAMPLER_1D_ARRAY: case eGL_INT_SAMPLER_2D_ARRAY: case eGL_INT_SAMPLER_2D_MULTISAMPLE: case eGL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case eGL_INT_SAMPLER_BUFFER: case eGL_INT_SAMPLER_2D_RECT: case eGL_UNSIGNED_INT_SAMPLER_1D: case eGL_UNSIGNED_INT_SAMPLER_2D: case eGL_UNSIGNED_INT_SAMPLER_3D: case eGL_UNSIGNED_INT_SAMPLER_CUBE: case eGL_UNSIGNED_INT_SAMPLER_1D_ARRAY: case eGL_UNSIGNED_INT_SAMPLER_2D_ARRAY: case eGL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: case eGL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: case eGL_UNSIGNED_INT_SAMPLER_BUFFER: case eGL_UNSIGNED_INT_SAMPLER_2D_RECT: case eGL_IMAGE_1D: case eGL_IMAGE_2D: case eGL_IMAGE_3D: case eGL_IMAGE_2D_RECT: case eGL_IMAGE_CUBE: case eGL_IMAGE_BUFFER: case eGL_IMAGE_1D_ARRAY: case eGL_IMAGE_2D_ARRAY: case eGL_IMAGE_CUBE_MAP_ARRAY: case eGL_IMAGE_2D_MULTISAMPLE: case eGL_IMAGE_2D_MULTISAMPLE_ARRAY: case eGL_INT_IMAGE_1D: case eGL_INT_IMAGE_2D: case eGL_INT_IMAGE_3D: case eGL_INT_IMAGE_2D_RECT: case eGL_INT_IMAGE_CUBE: case eGL_INT_IMAGE_BUFFER: case eGL_INT_IMAGE_1D_ARRAY: case eGL_INT_IMAGE_2D_ARRAY: case eGL_INT_IMAGE_2D_MULTISAMPLE: case eGL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: case eGL_UNSIGNED_INT_IMAGE_1D: case eGL_UNSIGNED_INT_IMAGE_2D: case eGL_UNSIGNED_INT_IMAGE_3D: case eGL_UNSIGNED_INT_IMAGE_2D_RECT: case eGL_UNSIGNED_INT_IMAGE_CUBE: case eGL_UNSIGNED_INT_IMAGE_BUFFER: case eGL_UNSIGNED_INT_IMAGE_1D_ARRAY: case eGL_UNSIGNED_INT_IMAGE_2D_ARRAY: case eGL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: case eGL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: case eGL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: case eGL_UNSIGNED_INT_ATOMIC_COUNTER: case eGL_INT: case eGL_INT_VEC2: case eGL_INT_VEC3: case eGL_INT_VEC4: baseType = VarType::Int; break; case eGL_UNSIGNED_INT: case eGL_BOOL: case eGL_UNSIGNED_INT_VEC2: case eGL_BOOL_VEC2: case eGL_UNSIGNED_INT_VEC3: case eGL_BOOL_VEC3: case eGL_UNSIGNED_INT_VEC4: case eGL_BOOL_VEC4: baseType = VarType::UInt; break; default: RDCERR("Unhandled uniform type '%s'", ToStr(el.Type).c_str()); baseType = VarType::Float; elemCount = 1; break; } switch(el.Type) { case eGL_FLOAT_MAT4: case eGL_DOUBLE_MAT4: elemCount = 16; break; case eGL_FLOAT_MAT4x3: case eGL_FLOAT_MAT3x4: case eGL_DOUBLE_MAT4x3: case eGL_DOUBLE_MAT3x4: elemCount = 12; break; case eGL_FLOAT_MAT4x2: case eGL_FLOAT_MAT2x4: case eGL_DOUBLE_MAT4x2: case eGL_DOUBLE_MAT2x4: elemCount = 8; break; case eGL_FLOAT_MAT3: case eGL_DOUBLE_MAT3: elemCount = 9; break; case eGL_FLOAT_MAT3x2: case eGL_DOUBLE_MAT3x2: case eGL_FLOAT_MAT2x3: case eGL_DOUBLE_MAT2x3: elemCount = 6; break; case eGL_FLOAT_MAT2: case eGL_DOUBLE_MAT2: case eGL_FLOAT_VEC4: case eGL_DOUBLE_VEC4: elemCount = 4; break; case eGL_FLOAT_VEC3: case eGL_DOUBLE_VEC3: elemCount = 3; break; case eGL_FLOAT_VEC2: case eGL_DOUBLE_VEC2: elemCount = 2; break; default: // all other types are elemCount = 1 break; } double *dv = el.data.dval; float *fv = el.data.fval; int32_t *iv = el.data.ival; uint32_t *uv = el.data.uval; if(baseType == VarType::Double) ser.Serialise("data", fv, elemCount, SerialiserFlags::NoFlags); else if(baseType == VarType::Float) ser.Serialise("data", dv, elemCount, SerialiserFlags::NoFlags); else if(baseType == VarType::Int) ser.Serialise("data", iv, elemCount, SerialiserFlags::NoFlags); else if(baseType == VarType::UInt) ser.Serialise("data", uv, elemCount, SerialiserFlags::NoFlags); }
void DoSerialise(SerialiserType &ser, D3D12Descriptor &el) { D3D12DescriptorType type = el.GetType(); ser.Serialise("type", type); ID3D12DescriptorHeap *heap = (ID3D12DescriptorHeap *)el.samp.heap; ser.Serialise("heap", heap); ser.Serialise("index", el.samp.idx); if(ser.IsReading()) { el.samp.heap = (WrappedID3D12DescriptorHeap *)heap; // for sampler types, this will be overwritten when serialising the sampler descriptor el.nonsamp.type = type; } switch(type) { case D3D12DescriptorType::Sampler: { ser.Serialise("Descriptor", el.samp.desc); RDCASSERTEQUAL(el.GetType(), D3D12DescriptorType::Sampler); break; } case D3D12DescriptorType::CBV: { ser.Serialise("Descriptor", el.nonsamp.cbv); break; } case D3D12DescriptorType::SRV: { ser.Serialise("Resource", el.nonsamp.resource); ser.Serialise("Descriptor", el.nonsamp.srv); break; } case D3D12DescriptorType::RTV: { ser.Serialise("Resource", el.nonsamp.resource); ser.Serialise("Descriptor", el.nonsamp.rtv); break; } case D3D12DescriptorType::DSV: { ser.Serialise("Resource", el.nonsamp.resource); ser.Serialise("Descriptor", el.nonsamp.dsv); break; } case D3D12DescriptorType::UAV: { ser.Serialise("Resource", el.nonsamp.resource); ser.Serialise("CounterResource", el.nonsamp.uav.counterResource); // special case because of extra resource and squeezed descriptor D3D12_UNORDERED_ACCESS_VIEW_DESC desc = el.nonsamp.uav.desc.AsDesc(); ser.Serialise("Descriptor", desc); el.nonsamp.uav.desc.Init(desc); break; } case D3D12DescriptorType::Undefined: { el.nonsamp.type = type; break; } } }
bool WrappedOpenGL::Serialise_wglDXLockObjectsNV(SerialiserType &ser, GLResource Resource) { SERIALISE_ELEMENT(Resource); SERIALISE_ELEMENT_LOCAL(textype, Resource.Namespace == eResBuffer ? eGL_NONE : m_Textures[GetResourceManager()->GetID(Resource)].curType) .Hidden(); const GLHookSet &gl = m_Real; // buffer contents are easier to save if(textype == eGL_NONE) { byte *Contents = NULL; uint32_t length = 1; // while writing, fetch the buffer's size and contents if(ser.IsWriting()) { gl.glGetNamedBufferParameterivEXT(Resource.name, eGL_BUFFER_SIZE, (GLint *)&length); Contents = new byte[length]; GLuint oldbuf = 0; gl.glGetIntegerv(eGL_COPY_READ_BUFFER_BINDING, (GLint *)&oldbuf); gl.glBindBuffer(eGL_COPY_READ_BUFFER, Resource.name); gl.glGetBufferSubData(eGL_COPY_READ_BUFFER, 0, (GLsizeiptr)length, Contents); gl.glBindBuffer(eGL_COPY_READ_BUFFER, oldbuf); } SERIALISE_ELEMENT_ARRAY(Contents, length); SERIALISE_CHECK_READ_ERRORS(); // restore on replay if(IsReplayingAndReading()) { uint32_t liveLength = 1; gl.glGetNamedBufferParameterivEXT(Resource.name, eGL_BUFFER_SIZE, (GLint *)&liveLength); gl.glNamedBufferSubData(Resource.name, 0, (GLsizeiptr)RDCMIN(length, liveLength), Contents); } } else { GLuint ppb = 0, pub = 0; PixelPackState pack; PixelUnpackState unpack; // save and restore pixel pack/unpack state. We only need one or the other but for clarity we // push and pop both always. if(ser.IsWriting() || !IsStructuredExporting(m_State)) { gl.glGetIntegerv(eGL_PIXEL_PACK_BUFFER_BINDING, (GLint *)&ppb); gl.glGetIntegerv(eGL_PIXEL_UNPACK_BUFFER_BINDING, (GLint *)&pub); gl.glBindBuffer(eGL_PIXEL_PACK_BUFFER, 0); gl.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, 0); pack.Fetch(&gl, false); unpack.Fetch(&gl, false); ResetPixelPackState(gl, false, 1); ResetPixelUnpackState(gl, false, 1); } TextureData &details = m_Textures[GetResourceManager()->GetID(Resource)]; GLuint tex = Resource.name; // serialise the metadata for convenience SERIALISE_ELEMENT_LOCAL(internalFormat, details.internalFormat).Hidden(); SERIALISE_ELEMENT_LOCAL(width, details.width).Hidden(); SERIALISE_ELEMENT_LOCAL(height, details.height).Hidden(); SERIALISE_ELEMENT_LOCAL(depth, details.depth).Hidden(); RDCASSERT(internalFormat == details.internalFormat, internalFormat, details.internalFormat); RDCASSERT(width == details.width, width, details.width); RDCASSERT(height == details.height, height, details.height); RDCASSERT(depth == details.depth, depth, details.depth); GLenum fmt = GetBaseFormat(internalFormat); GLenum type = GetDataType(internalFormat); GLint dim = details.dimension; uint32_t size = (uint32_t)GetByteSize(width, height, depth, fmt, type); int mips = 0; if(IsReplayingAndReading()) mips = GetNumMips(gl, textype, tex, width, height, depth); byte *scratchBuf = NULL; // on read and write, we allocate a single buffer big enough for all mips and re-use it // to avoid repeated new/free. scratchBuf = AllocAlignedBuffer(size); GLuint prevtex = 0; if(!IsStructuredExporting(m_State)) { gl.glGetIntegerv(TextureBinding(details.curType), (GLint *)&prevtex); gl.glBindTexture(textype, tex); } for(int i = 0; i < mips; i++) { int w = RDCMAX(details.width >> i, 1); int h = RDCMAX(details.height >> i, 1); int d = RDCMAX(details.depth >> i, 1); if(textype == eGL_TEXTURE_CUBE_MAP_ARRAY || textype == eGL_TEXTURE_1D_ARRAY || textype == eGL_TEXTURE_2D_ARRAY) d = details.depth; size = (uint32_t)GetByteSize(w, h, d, fmt, type); GLenum targets[] = { eGL_TEXTURE_CUBE_MAP_POSITIVE_X, eGL_TEXTURE_CUBE_MAP_NEGATIVE_X, eGL_TEXTURE_CUBE_MAP_POSITIVE_Y, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Y, eGL_TEXTURE_CUBE_MAP_POSITIVE_Z, eGL_TEXTURE_CUBE_MAP_NEGATIVE_Z, }; int count = ARRAY_COUNT(targets); if(textype != eGL_TEXTURE_CUBE_MAP) { targets[0] = textype; count = 1; } for(int trg = 0; trg < count; trg++) { if(ser.IsWriting()) { // we avoid glGetTextureImageEXT as it seems buggy for cubemap faces gl.glGetTexImage(targets[trg], i, fmt, type, scratchBuf); } // serialise without allocating memory as we already have our scratch buf sized. ser.Serialise("SubresourceContents", scratchBuf, size, SerialiserFlags::NoFlags); if(IsReplayingAndReading() && !ser.IsErrored()) { if(dim == 1) gl.glTextureSubImage1DEXT(tex, targets[trg], i, 0, w, fmt, type, scratchBuf); else if(dim == 2) gl.glTextureSubImage2DEXT(tex, targets[trg], i, 0, 0, w, h, fmt, type, scratchBuf); else if(dim == 3) gl.glTextureSubImage3DEXT(tex, targets[trg], i, 0, 0, 0, w, h, d, fmt, type, scratchBuf); } } } FreeAlignedBuffer(scratchBuf); // restore pixel (un)packing state if(ser.IsWriting() || !IsStructuredExporting(m_State)) { gl.glBindBuffer(eGL_PIXEL_PACK_BUFFER, ppb); gl.glBindBuffer(eGL_PIXEL_UNPACK_BUFFER, pub); pack.Apply(&gl, false); unpack.Apply(&gl, false); } if(!IsStructuredExporting(m_State)) gl.glBindTexture(textype, prevtex); SERIALISE_CHECK_READ_ERRORS(); } return true; }