Ejemplo n.º 1
0
  ImageViewer(IReplayDriver *proxy, const char *filename)
      : m_Proxy(proxy), m_Filename(filename), m_TextureID()
  {
    if(m_Proxy == NULL)
      RDCERR("Unexpectedly NULL proxy at creation of ImageViewer");

    m_Props.pipelineType = ePipelineState_D3D11;
    m_Props.degraded = false;

    m_FrameRecord.frameInfo.fileOffset = 0;
    m_FrameRecord.frameInfo.firstEvent = 1;
    m_FrameRecord.frameInfo.frameNumber = 1;
    m_FrameRecord.frameInfo.immContextId = ResourceId();
    RDCEraseEl(m_FrameRecord.frameInfo.stats);

    create_array_uninit(m_FrameRecord.drawcallList, 1);
    FetchDrawcall &d = m_FrameRecord.drawcallList[0];
    d.context = ResourceId();
    d.drawcallID = 1;
    d.eventID = 1;
    d.name = filename;

    RefreshFile();

    create_array_uninit(m_PipelineState.m_OM.RenderTargets, 1);
    m_PipelineState.m_OM.RenderTargets[0].Resource = m_TextureID;
  }
Ejemplo n.º 2
0
		ImageViewer(IReplayDriver *proxy, const char *filename, ResourceId texID)
			: m_Proxy(proxy)
		{
			if(m_Proxy == NULL) RDCERR("Unexpectedly NULL proxy at creation of ImageViewer");

			m_Props.pipelineType = ePipelineState_D3D11;
			m_Props.degraded = false;
			
			FetchFrameRecord record;
			record.frameInfo.fileOffset = 0;
			record.frameInfo.firstEvent = 1;
			record.frameInfo.frameNumber = 1;
			record.frameInfo.immContextId = ResourceId();

			FetchDrawcall d;
			d.context = record.frameInfo.immContextId;
			d.drawcallID = 1;
			d.eventID = 1;
			d.name = filename;

			record.drawcallList.push_back(d);
			
			create_array_uninit(m_PipelineState.m_OM.RenderTargets, 1);
			m_PipelineState.m_OM.RenderTargets[0].Resource = texID;

			m_FrameRecord.push_back(record);
		}
Ejemplo n.º 3
0
bool ReplayRenderer::GetFrameInfo(rdctype::array<FetchFrameInfo> *arr)
{
	if(arr == NULL) return false;

	create_array_uninit(*arr, m_FrameRecord.size());
	for(size_t i=0; i < m_FrameRecord.size(); i++)
		arr->elems[i] = m_FrameRecord[i].frameInfo;

	return true;
}
Ejemplo n.º 4
0
bool ReplayRenderer::GetResolve(uint64_t *callstack, uint32_t callstackLen, rdctype::array<rdctype::wstr> *arr)
{
	if(arr == NULL || callstack == NULL || callstackLen == 0) return false;

	Callstack::StackResolver *resolv = m_pDevice->GetCallstackResolver();

	if(resolv == NULL)
	{
		create_array_uninit(*arr, 1);
		arr->elems[0] = L"";
		return true;
	}

	create_array_uninit(*arr, callstackLen);
	for(size_t i=0; i < callstackLen; i++)
	{
		Callstack::AddressDetails info = resolv->GetAddr(callstack[i]);
		arr->elems[i] = info.formattedString();
	}

	return true;
}
Ejemplo n.º 5
0
bool WrappedOpenGL::Serialise_glCompileShader(GLuint shader)
{
	SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(ShaderRes(GetCtx(), shader)));
	
	if(m_State == READING)
	{
		ResourceId liveId = GetResourceManager()->GetLiveID(id);

		auto &shadDetails = m_Shaders[liveId];

		bool pointSizeUsed = false, clipDistanceUsed = false;
		if(shadDetails.type == eGL_VERTEX_SHADER) CheckVertexOutputUses(shadDetails.sources, pointSizeUsed, clipDistanceUsed);

		GLuint sepProg = MakeSeparableShaderProgram(m_Real, shadDetails.type, shadDetails.sources, NULL);

		if(sepProg == 0)
		{
			RDCERR("Couldn't make separable program for shader via patching - functionality will be broken.");
		}
		else
		{
			shadDetails.prog = sepProg;
			MakeShaderReflection(m_Real, shadDetails.type, sepProg, shadDetails.reflection, pointSizeUsed, clipDistanceUsed);

			string s = CompileSPIRV(SPIRVShaderStage(ShaderIdx(shadDetails.type)), shadDetails.sources, shadDetails.spirv);
			if(!shadDetails.spirv.empty())
				DisassembleSPIRV(SPIRVShaderStage(ShaderIdx(shadDetails.type)), shadDetails.spirv, s);

			shadDetails.reflection.Disassembly = s;

			create_array_uninit(shadDetails.reflection.DebugInfo.files, shadDetails.sources.size());
			for(size_t i=0; i < shadDetails.sources.size(); i++)
			{
				shadDetails.reflection.DebugInfo.files[i].first = StringFormat::Fmt("source%u.glsl", (uint32_t)i);
				shadDetails.reflection.DebugInfo.files[i].second = shadDetails.sources[i];
			}
		}

		m_Real.glCompileShader(GetResourceManager()->GetLiveResource(id).name);
	}

	return true;
}
Ejemplo n.º 6
0
void WrappedOpenGL::ShaderData::Compile(WrappedOpenGL &gl)
{
  bool pointSizeUsed = false, clipDistanceUsed = false;
  if(type == eGL_VERTEX_SHADER)
    CheckVertexOutputUses(sources, pointSizeUsed, clipDistanceUsed);

  GLuint sepProg = prog;

  if(sepProg == 0)
    sepProg = MakeSeparableShaderProgram(gl, type, sources, NULL);

  if(sepProg == 0)
  {
    RDCERR(
        "Couldn't make separable program for shader via patching - functionality will be broken.");
  }
  else
  {
    prog = sepProg;
    MakeShaderReflection(gl.GetHookset(), type, sepProg, reflection, pointSizeUsed, clipDistanceUsed);

    vector<uint32_t> spirvwords;

    string s = CompileSPIRV(SPIRVShaderStage(ShaderIdx(type)), sources, spirvwords);
    if(!spirvwords.empty())
      ParseSPIRV(&spirvwords.front(), spirvwords.size(), spirv);

    // for classic GL, entry point is always main
    reflection.Disassembly = spirv.Disassemble("main");

    create_array_uninit(reflection.DebugInfo.files, sources.size());
    for(size_t i = 0; i < sources.size(); i++)
    {
      reflection.DebugInfo.files[i].first = StringFormat::Fmt("source%u.glsl", (uint32_t)i);
      reflection.DebugInfo.files[i].second = sources[i];
    }
  }
}
Ejemplo n.º 7
0
  void ReceiveMessage(RemoteMessage *msg)
  {
    if(m_Socket == NULL)
    {
      msg->Type = eRemoteMsg_Disconnected;
      return;
    }

    if(!m_Socket->IsRecvDataWaiting())
    {
      if(!m_Socket->Connected())
      {
        SAFE_DELETE(m_Socket);
        msg->Type = eRemoteMsg_Disconnected;
      }
      else
      {
        Threading::Sleep(2);
        msg->Type = eRemoteMsg_Noop;
      }

      return;
    }

    PacketType type;
    Serialiser *ser = NULL;

    GetPacket(type, ser);

    if(m_Socket == NULL)
    {
      SAFE_DELETE(ser);

      msg->Type = eRemoteMsg_Disconnected;
      return;
    }
    else
    {
      if(type == ePacket_Noop)
      {
        SAFE_DELETE(ser);

        msg->Type = eRemoteMsg_Noop;
        return;
      }
      else if(type == ePacket_Busy)
      {
        string existingClient;
        ser->Serialise("", existingClient);

        SAFE_DELETE(ser);

        SAFE_DELETE(m_Socket);

        RDCLOG("Got busy signal: '%s", existingClient.c_str());
        msg->Type = eRemoteMsg_Busy;
        msg->Busy.ClientName = existingClient;
        return;
      }
      else if(type == ePacket_CopyCapture)
      {
        msg->Type = eRemoteMsg_CaptureCopied;

        ser->Serialise("", msg->NewCapture.ID);

        SAFE_DELETE(ser);

        msg->NewCapture.localpath = m_CaptureCopies[msg->NewCapture.ID];

        if(!RecvChunkedFile(m_Socket, ePacket_CopyCapture, msg->NewCapture.localpath.elems, ser, NULL))
        {
          SAFE_DELETE(ser);
          SAFE_DELETE(m_Socket);

          msg->Type = eRemoteMsg_Disconnected;
          return;
        }

        m_CaptureCopies.erase(msg->NewCapture.ID);

        SAFE_DELETE(ser);

        return;
      }
      else if(type == ePacket_NewChild)
      {
        msg->Type = eRemoteMsg_NewChild;

        ser->Serialise("", msg->NewChild.PID);
        ser->Serialise("", msg->NewChild.ident);

        RDCLOG("Got a new child process: %u %u", msg->NewChild.PID, msg->NewChild.ident);

        SAFE_DELETE(ser);

        return;
      }
      else if(type == ePacket_NewCapture)
      {
        msg->Type = eRemoteMsg_NewCapture;

        ser->Serialise("", msg->NewCapture.ID);
        ser->Serialise("", msg->NewCapture.timestamp);

        string path;
        ser->Serialise("", path);
        msg->NewCapture.localpath = path;

        if(!m_Local)
          msg->NewCapture.localpath = "";

        uint32_t thumblen = 0;
        ser->Serialise("", thumblen);

        create_array_uninit(msg->NewCapture.thumbnail, thumblen);

        size_t l = 0;
        byte *buf = &msg->NewCapture.thumbnail[0];
        ser->SerialiseBuffer("", buf, l);

        RDCLOG("Got a new capture: %d (time %llu) %d byte thumbnail", msg->NewCapture.ID,
               msg->NewCapture.timestamp, thumblen);

        SAFE_DELETE(ser);

        return;
      }
      else if(type == ePacket_RegisterAPI)
      {
        msg->Type = eRemoteMsg_RegisterAPI;

        ser->Serialise("", m_API);
        msg->RegisterAPI.APIName = m_API;

        RDCLOG("Used API: %s", m_API.c_str());

        SAFE_DELETE(ser);

        return;
      }
    }

    SAFE_DELETE(ser);

    msg->Type = eRemoteMsg_Noop;
  }
Ejemplo n.º 8
0
void GLReplay::SavePipelineState()
{
	GLPipelineState &pipe = m_CurPipelineState;
	WrappedOpenGL &gl = *m_pDriver;
	GLResourceManager *rm = m_pDriver->GetResourceManager();

	MakeCurrentReplayContext(&m_ReplayCtx);

	// Index buffer

	pipe.m_VtxIn.ibuffer.Offset = m_pDriver->m_LastIndexOffset;
	
	pipe.m_VtxIn.ibuffer.Format = ResourceFormat();
	pipe.m_VtxIn.ibuffer.Format.special = false;
	pipe.m_VtxIn.ibuffer.Format.compCount = 1;
	pipe.m_VtxIn.ibuffer.Format.compType = eCompType_UInt;
	switch(m_pDriver->m_LastIndexSize)
	{
		default:
			break;
		case eGL_UNSIGNED_BYTE:
			pipe.m_VtxIn.ibuffer.Format.compByteWidth = 1;
			pipe.m_VtxIn.ibuffer.Format.strname = L"GL_UNSIGNED_BYTE";
			break;
		case eGL_UNSIGNED_SHORT:
			pipe.m_VtxIn.ibuffer.Format.compByteWidth = 2;
			pipe.m_VtxIn.ibuffer.Format.strname = L"GL_UNSIGNED_SHORT";
			break;
		case eGL_UNSIGNED_INT:
			pipe.m_VtxIn.ibuffer.Format.compByteWidth = 4;
			pipe.m_VtxIn.ibuffer.Format.strname = L"GL_UNSIGNED_INT";
			break;
	}

	GLint curIdxBuf = 0;
	gl.glGetIntegerv(eGL_ELEMENT_ARRAY_BUFFER_BINDING, &curIdxBuf);

	pipe.m_VtxIn.ibuffer.Buffer = rm->GetOriginalID(rm->GetID(BufferRes(curIdxBuf)));

	// Vertex buffers and attributes
	GLint numVBufferBindings = 16;
	gl.glGetIntegerv(eGL_MAX_VERTEX_ATTRIB_BINDINGS, &numVBufferBindings);
	
	GLint numVAttribBindings = 16;
	gl.glGetIntegerv(eGL_MAX_VERTEX_ATTRIBS, &numVAttribBindings);

	create_array_uninit(pipe.m_VtxIn.vbuffers, numVBufferBindings);
	create_array_uninit(pipe.m_VtxIn.attributes, numVAttribBindings);

	for(GLuint i=0; i < (GLuint)numVBufferBindings; i++)
	{
		GLint vb = 0;
		gl.glGetIntegeri_v(eGL_VERTEX_BINDING_BUFFER, i, &vb);
		pipe.m_VtxIn.vbuffers[i].Buffer = rm->GetOriginalID(rm->GetID(BufferRes(vb)));

		gl.glGetIntegeri_v(eGL_VERTEX_BINDING_STRIDE, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Stride);
		gl.glGetIntegeri_v(eGL_VERTEX_BINDING_OFFSET, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Offset);
		gl.glGetIntegeri_v(eGL_VERTEX_BINDING_DIVISOR, i, (GLint *)&pipe.m_VtxIn.vbuffers[i].Divisor);
		pipe.m_VtxIn.vbuffers[i].PerInstance = (pipe.m_VtxIn.vbuffers[i].Divisor != 0);
	}
	
	for(GLuint i=0; i < (GLuint)numVAttribBindings; i++)
	{
		gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_ENABLED, (GLint *)&pipe.m_VtxIn.attributes[i].Enabled);
		gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_BINDING, (GLint *)&pipe.m_VtxIn.attributes[i].BufferSlot);
		gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_RELATIVE_OFFSET, (GLint*)&pipe.m_VtxIn.attributes[i].RelativeOffset);

		GLenum type = eGL_FLOAT;
		GLint normalized = 0;
		
		gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_TYPE, (GLint *)&type);
		gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &normalized);

		ResourceFormat fmt;

		fmt.special = false;
		fmt.compCount = 4;
		gl.glGetVertexAttribiv(i, eGL_VERTEX_ATTRIB_ARRAY_SIZE, (GLint *)&fmt.compCount);
		
		switch(type)
		{
			default:
			case eGL_BYTE:
				fmt.compByteWidth = 1;
				fmt.compType = normalized ? eCompType_SInt : eCompType_SNorm;
				fmt.strname = StringFormat::WFmt(L"GL_BYTE%d", fmt.compCount) + (normalized ? L"" : L"_SNORM");
				break;
			case eGL_UNSIGNED_BYTE:
				fmt.compByteWidth = 1;
				fmt.compType = normalized ? eCompType_UInt : eCompType_UNorm;
				fmt.strname = StringFormat::WFmt(L"GL_UNSIGNED_BYTE%d", fmt.compCount) + (normalized ? L"" : L"_UNORM");
				break;
			case eGL_SHORT:
				fmt.compByteWidth = 2;
				fmt.compType = normalized ? eCompType_SInt : eCompType_SNorm;
				fmt.strname = StringFormat::WFmt(L"GL_SHORT%d", fmt.compCount) + (normalized ? L"" : L"_SNORM");
				break;
			case eGL_UNSIGNED_SHORT:
				fmt.compByteWidth = 2;
				fmt.compType = normalized ? eCompType_UInt : eCompType_UNorm;
				fmt.strname = StringFormat::WFmt(L"GL_UNSIGNED_SHORT%d", fmt.compCount) + (normalized ? L"" : L"_UNORM");
				break;
			case eGL_INT:
				fmt.compByteWidth = 4;
				fmt.compType = normalized ? eCompType_SInt : eCompType_SNorm;
				fmt.strname = StringFormat::WFmt(L"GL_INT%d", fmt.compCount) + (normalized ? L"" : L"_SNORM");
				break;
			case eGL_UNSIGNED_INT:
				fmt.compByteWidth = 4;
				fmt.compType = normalized ? eCompType_UInt : eCompType_UNorm;
				fmt.strname = StringFormat::WFmt(L"GL_UNSIGNED_INT%d", fmt.compCount) + (normalized ? L"" : L"_UNORM");
				break;
			case eGL_FLOAT:
				fmt.compByteWidth = 4;
				fmt.compType = eCompType_Float;
				fmt.strname = StringFormat::WFmt(L"GL_FLOAT%d", fmt.compCount);
				break;
			case eGL_DOUBLE:
				fmt.compByteWidth = 8;
				fmt.compType = eCompType_Double;
				fmt.strname = StringFormat::WFmt(L"GL_DOUBLE%d", fmt.compCount);
				break;
			case eGL_HALF_FLOAT:
				fmt.compByteWidth = 2;
				fmt.compType = eCompType_Float;
				fmt.strname = StringFormat::WFmt(L"GL_HALF_FLOAT%d", fmt.compCount);
				break;
			case eGL_INT_2_10_10_10_REV:
				fmt.special = true;
				fmt.specialFormat = eSpecial_R10G10B10A2;
				fmt.compCount = 4;
				fmt.compType = eCompType_UInt;
				fmt.strname = L"GL_INT_2_10_10_10_REV";
				break;
			case eGL_UNSIGNED_INT_2_10_10_10_REV:
				fmt.special = true;
				fmt.specialFormat = eSpecial_R10G10B10A2;
				fmt.compCount = 4;
				fmt.compType = eCompType_SInt;
				fmt.strname = L"eGL_UNSIGNED_INT_2_10_10_10_REV";
				break;
			case eGL_UNSIGNED_INT_10F_11F_11F_REV:
				fmt.special = true;
				fmt.specialFormat = eSpecial_R11G11B10;
				fmt.compCount = 3;
				fmt.compType = eCompType_SInt;
				fmt.strname = L"eGL_UNSIGNED_INT_10F_11F_11F_REV";
				break;
		}

		pipe.m_VtxIn.attributes[i].Format = fmt;
	}

	switch(m_pDriver->m_LastDrawMode)
	{
		default:
			pipe.m_VtxIn.Topology = eTopology_Unknown;
			break;
		case GL_POINTS:
			pipe.m_VtxIn.Topology = eTopology_PointList;
			break;
		case GL_LINE_STRIP:
			pipe.m_VtxIn.Topology = eTopology_LineStrip;
			break;
		case GL_LINE_LOOP:
			pipe.m_VtxIn.Topology = eTopology_LineLoop;
			break;
		case GL_LINES:
			pipe.m_VtxIn.Topology = eTopology_LineList;
			break;
		case GL_LINE_STRIP_ADJACENCY:
			pipe.m_VtxIn.Topology = eTopology_LineStrip_Adj;
			break;
		case GL_LINES_ADJACENCY:
			pipe.m_VtxIn.Topology = eTopology_LineList_Adj;
			break;
		case GL_TRIANGLE_STRIP:
			pipe.m_VtxIn.Topology = eTopology_TriangleStrip;
			break;
		case GL_TRIANGLE_FAN:
			pipe.m_VtxIn.Topology = eTopology_TriangleFan;
			break;
		case GL_TRIANGLES:
			pipe.m_VtxIn.Topology = eTopology_TriangleList;
			break;
		case GL_TRIANGLE_STRIP_ADJACENCY:
			pipe.m_VtxIn.Topology = eTopology_TriangleStrip_Adj;
			break;
		case GL_TRIANGLES_ADJACENCY:
			pipe.m_VtxIn.Topology = eTopology_TriangleList_Adj;
			break;
		case GL_PATCHES:
		{
			GLint patchCount = 3;
			gl.glGetIntegerv(eGL_PATCH_VERTICES, &patchCount);
			pipe.m_VtxIn.Topology = PrimitiveTopology(eTopology_PatchList_1CPs+patchCount);
			break;
		}
	}

	// Shader stages
	
	GLuint curProg = 0;
	gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint*)&curProg);
	
	auto &progDetails = m_pDriver->m_Programs[rm->GetID(ProgramRes(curProg))];

	RDCASSERT(progDetails.shaders.size());

	for(size_t i=0; i < progDetails.shaders.size(); i++)
	{
		if(m_pDriver->m_Shaders[ progDetails.shaders[i] ].type == eGL_VERTEX_SHADER)
			pipe.m_VS.Shader = rm->GetOriginalID(progDetails.shaders[i]);
		else if(m_pDriver->m_Shaders[ progDetails.shaders[i] ].type == eGL_FRAGMENT_SHADER)
			pipe.m_FS.Shader = rm->GetOriginalID(progDetails.shaders[i]);
	}
	
	pipe.m_VS.stage = eShaderStage_Vertex;
	pipe.m_TCS.stage = eShaderStage_Tess_Control;
	pipe.m_TES.stage = eShaderStage_Tess_Eval;
	pipe.m_GS.stage = eShaderStage_Geometry;
	pipe.m_FS.stage = eShaderStage_Fragment;
	pipe.m_CS.stage = eShaderStage_Compute;

	// Textures
	
	GLint numTexUnits = 8;
	gl.glGetIntegerv(eGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &numTexUnits);
	create_array_uninit(pipe.Textures, numTexUnits);

	GLenum activeTexture = eGL_TEXTURE0;
	gl.glGetIntegerv(eGL_ACTIVE_TEXTURE, (GLint*)&activeTexture);

	// GL is ass-backwards in its handling of texture units. When a shader is active
	// the types in the glsl samplers inform which targets are used from which texture units
	//
	// So texture unit 5 can have a 2D bound (texture 52) and a Cube bound (texture 77).
	// * if a uniform sampler2D has value 5 then the 2D texture is used, and we sample from 52
	// * if a uniform samplerCube has value 5 then the Cube texture is used, and we sample from 77
	// It's illegal for both a sampler2D and samplerCube to both have the same value (or any two
	// different types). It makes it all rather pointless and needlessly complex.
	//
	// What we have to do then, is consider the program, look at the values of the uniforms, and
	// then get the appropriate current binding based on the uniform type. We can warn/alert the
	// user if we hit the illegal case of two uniforms with different types but the same value
	//
	// Handling is different if no shaders are active, but we don't consider that case.


	// prefetch uniform values in GetShader()
	ShaderReflection *refls[6];
	for(size_t s=0; s < progDetails.shaders.size(); s++)
		refls[s] = GetShader(progDetails.shaders[s]);

	for(GLint unit=0; unit < numTexUnits; unit++)
	{
		GLenum binding = eGL_UNKNOWN_ENUM;
		GLenum target = eGL_UNKNOWN_ENUM;
		
		for(size_t s=0; s < progDetails.shaders.size(); s++)
		{
			if(refls[s] == NULL) continue;

			for(int32_t r=0; r < refls[s]->Resources.count; r++)
			{
				// bindPoint is the uniform value for this sampler
				if(refls[s]->Resources[r].bindPoint == (uint32_t)unit)
				{
					GLenum t = eGL_UNKNOWN_ENUM;

					switch(refls[s]->Resources[r].resType)
					{
						case eResType_None:
							t = eGL_UNKNOWN_ENUM;
							break;
						case eResType_Buffer:
							t = eGL_TEXTURE_BINDING_BUFFER;
							break;
						case eResType_Texture1D:
							t = eGL_TEXTURE_BINDING_1D;
							target = eGL_TEXTURE_1D;
							break;
						case eResType_Texture1DArray:
							t = eGL_TEXTURE_BINDING_1D_ARRAY;
							target = eGL_TEXTURE_1D_ARRAY;
							break;
						case eResType_Texture2D:
							t = eGL_TEXTURE_BINDING_2D;
							target = eGL_TEXTURE_2D;
							break;
						case eResType_Texture2DArray:
							t = eGL_TEXTURE_BINDING_2D_ARRAY;
							target = eGL_TEXTURE_2D_ARRAY;
							break;
						case eResType_Texture2DMS:
							t = eGL_TEXTURE_BINDING_2D_MULTISAMPLE;
							target = eGL_TEXTURE_2D_MULTISAMPLE;
							break;
						case eResType_Texture2DMSArray:
							t = eGL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY;
							target = eGL_TEXTURE_2D_MULTISAMPLE_ARRAY;
							break;
						case eResType_Texture3D:
							t = eGL_TEXTURE_BINDING_3D;
							target = eGL_TEXTURE_3D;
							break;
						case eResType_TextureCube:
							t = eGL_TEXTURE_BINDING_CUBE_MAP;
							target = eGL_TEXTURE_CUBE_MAP;
							break;
						case eResType_TextureCubeArray:
							t = eGL_TEXTURE_BINDING_CUBE_MAP_ARRAY;
							target = eGL_TEXTURE_CUBE_MAP_ARRAY;
							break;
					}

					if(binding == eGL_UNKNOWN_ENUM)
					{
						binding = t;
					}
					else if(binding == t)
					{
						// two uniforms with the same type pointing to the same slot is fine
						binding = t;
					}
					else if(binding != t)
					{
						RDCWARN("Two uniforms pointing to texture unit %d with types %s and %s", unit, ToStr::Get(binding).c_str(), ToStr::Get(t).c_str());
					}
				}
			}
		}

		if(binding != eGL_UNKNOWN_ENUM)
		{
			gl.glActiveTexture(GLenum(eGL_TEXTURE0+unit));

			GLuint tex;
			gl.glGetIntegerv(binding, (GLint *)&tex);

			// very bespoke/specific
			GLint firstSlice = 0;
			gl.glGetTexParameteriv(target, eGL_TEXTURE_VIEW_MIN_LEVEL, &firstSlice);

			pipe.Textures[unit].Resource = rm->GetOriginalID(rm->GetID(TextureRes(tex)));
			pipe.Textures[unit].FirstSlice = (uint32_t)firstSlice;
		}
		else
		{
			// what should we do in this case? there could be something bound just not used,
			// it'd be nice to return that
		}
	}

	gl.glActiveTexture(activeTexture);

	GLuint curFBO = 0;
	gl.glGetIntegerv(eGL_DRAW_FRAMEBUFFER_BINDING, (GLint*)&curFBO);
	
	GLint numCols = 8;
	gl.glGetIntegerv(eGL_MAX_COLOR_ATTACHMENTS, &numCols);

	GLuint curCol[32] = { 0 };
	GLuint curDepth = 0;
	GLuint curStencil = 0;

	RDCASSERT(numCols <= 32);

	// we should never bind the true default framebuffer - if the app did, we will have our fake bound
	RDCASSERT(curFBO != 0);

	{
		for(GLint i=0; i < numCols; i++)
			gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, GLenum(eGL_COLOR_ATTACHMENT0+i), eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint*)&curCol[i]);
		gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_DEPTH_ATTACHMENT, eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint*)&curDepth);
		gl.glGetFramebufferAttachmentParameteriv(eGL_DRAW_FRAMEBUFFER, eGL_STENCIL_ATTACHMENT, eGL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, (GLint*)&curStencil);
	}

	pipe.m_FB.FBO = rm->GetOriginalID(rm->GetID(FramebufferRes(curFBO)));
	create_array_uninit(pipe.m_FB.Color, numCols);
	for(GLint i=0; i < numCols; i++)
		pipe.m_FB.Color[i] = rm->GetOriginalID(rm->GetID(TextureRes(curCol[i])));

	pipe.m_FB.Depth = rm->GetOriginalID(rm->GetID(TextureRes(curDepth)));
	pipe.m_FB.Stencil = rm->GetOriginalID(rm->GetID(TextureRes(curStencil)));
}
Ejemplo n.º 9
0
ShaderReflection *GLReplay::GetShader(ResourceId id)
{
	WrappedOpenGL &gl = *m_pDriver;
	
	MakeCurrentReplayContext(&m_ReplayCtx);
	
	GLuint curProg = 0;
	gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint*)&curProg);
	
	auto &progDetails = m_pDriver->m_Programs[m_pDriver->GetResourceManager()->GetID(ProgramRes(curProg))];
	auto &shaderDetails = m_pDriver->m_Shaders[id];

	auto &refl = shaderDetails.reflection;

	// initialise reflection data
	// TODO: do this earlier. In glLinkProgram?
	if(refl.DebugInfo.files.count == 0)
	{
		refl.DebugInfo.entryFunc = "main";
		refl.DebugInfo.compileFlags = 0;
		create_array_uninit(refl.DebugInfo.files, shaderDetails.sources.size());
		for(size_t i=0; i < shaderDetails.sources.size(); i++)
		{
			refl.DebugInfo.files[i].first = StringFormat::Fmt("source%u.glsl", (uint32_t)i);
			refl.DebugInfo.files[i].second = shaderDetails.sources[i];
		}

		refl.Disassembly = "";

		vector<ShaderResource> resources;

		GLint numUniforms = 0;
		gl.glGetProgramInterfaceiv(curProg, eGL_UNIFORM, eGL_ACTIVE_RESOURCES, &numUniforms);

		const size_t numProps = 6;

		GLenum resProps[numProps] = {
			eGL_REFERENCED_BY_VERTEX_SHADER,
			
			eGL_TYPE, eGL_NAME_LENGTH, eGL_LOCATION, eGL_BLOCK_INDEX, eGL_ARRAY_SIZE,
		};

		if(shaderDetails.type == eGL_VERTEX_SHADER)          resProps[0] = eGL_REFERENCED_BY_VERTEX_SHADER;
		if(shaderDetails.type == eGL_TESS_CONTROL_SHADER)    resProps[0] = eGL_REFERENCED_BY_TESS_CONTROL_SHADER;
		if(shaderDetails.type == eGL_TESS_EVALUATION_SHADER) resProps[0] = eGL_REFERENCED_BY_TESS_EVALUATION_SHADER;
		if(shaderDetails.type == eGL_GEOMETRY_SHADER)        resProps[0] = eGL_REFERENCED_BY_GEOMETRY_SHADER;
		if(shaderDetails.type == eGL_FRAGMENT_SHADER)        resProps[0] = eGL_REFERENCED_BY_FRAGMENT_SHADER;
		if(shaderDetails.type == eGL_COMPUTE_SHADER)         resProps[0] = eGL_REFERENCED_BY_COMPUTE_SHADER;
		
		for(GLint u=0; u < numUniforms; u++)
		{
			GLint values[numProps];
			gl.glGetProgramResourceiv(curProg, eGL_UNIFORM, u, numProps, resProps, numProps, NULL, values);

			// skip if unused by this stage
			if(values[0] == GL_FALSE)
				continue;
			
			ShaderResource res;
			res.IsSampler = false; // no separate sampler objects in GL

			if(values[1] == GL_SAMPLER_2D)
			{
				res.IsSRV = true;
				res.IsTexture = true;
				res.IsUAV = false;
				res.resType = eResType_Texture2D;
				res.variableType.descriptor.name = "sampler2D";
				res.variableType.descriptor.rows = 1;
				res.variableType.descriptor.cols = 4;
				res.variableType.descriptor.elements = 1;
			}
			else if(values[1] == GL_INT_SAMPLER_1D)
			{
				res.IsSRV = true;
				res.IsTexture = true;
				res.IsUAV = false;
				res.resType = eResType_Texture1D;
				res.variableType.descriptor.name = "isampler1D";
				res.variableType.descriptor.rows = 1;
				res.variableType.descriptor.cols = 4;
				res.variableType.descriptor.elements = 1;
			}
			else
			{
				// fill in more sampler types
				continue;
			}

			res.variableAddress = values[3];

			create_array_uninit(res.name, values[2]+1);
			gl.glGetProgramResourceName(curProg, eGL_UNIFORM, u, values[2]+1, NULL, res.name.elems);
			res.name.count--; // trim off trailing null

			resources.push_back(res);
		}

		refl.Resources = resources;

		vector<ShaderConstant> globalUniforms;

		for(GLint u=0; u < numUniforms; u++)
		{
			GLint values[numProps];
			gl.glGetProgramResourceiv(curProg, eGL_UNIFORM, u, numProps, resProps, numProps, NULL, values);
			
			// skip if unused by this stage
			if(values[0] == GL_FALSE)
				continue;

			// don't look at block uniforms just yet
			if(values[4] != -1)
			{
				GLNOTIMP("Not fetching uniforms in UBOs (should become their own ConstantBlocks)");
				continue;
			}
			
			ShaderConstant var;
			
			if(values[1] == GL_FLOAT_VEC4)
			{
				var.type.descriptor.name = "vec4";
				var.type.descriptor.rows = 1;
				var.type.descriptor.cols = 4;
				var.type.descriptor.elements = values[5];
			}
			else if(values[1] == GL_FLOAT_VEC3)
			{
				var.type.descriptor.name = "vec3";
				var.type.descriptor.rows = 1;
				var.type.descriptor.cols = 3;
				var.type.descriptor.elements = values[5];
			}
			else if(values[1] == GL_FLOAT_MAT4)
			{
				var.type.descriptor.name = "mat4";
				var.type.descriptor.rows = 4;
				var.type.descriptor.cols = 4;
				var.type.descriptor.elements = values[5];
			}
			else
			{
				// fill in more uniform types
				continue;
			}

			var.reg.vec = values[3];
			var.reg.comp = 0;

			create_array_uninit(var.name, values[2]+1);
			gl.glGetProgramResourceName(curProg, eGL_UNIFORM, u, values[2]+1, NULL, var.name.elems);
			var.name.count--; // trim off trailing null

			if(strchr(var.name.elems, '.'))
			{
				GLNOTIMP("Variable contains . - structure not reconstructed");
			}

			globalUniforms.push_back(var);
		}

		vector<ConstantBlock> cbuffers;

		if(!globalUniforms.empty())
		{
			ConstantBlock globals;
			globals.name = "Globals";
			globals.bufferAddress = -1;
			globals.variables = globalUniforms;

			cbuffers.push_back(globals);
		}

		// here we would iterate over UNIFORM_BLOCKs or similar

		// TODO: fill in Interfaces with shader subroutines?
		// TODO: find a way of generating input/output signature.
		//       The only way I can think of doing this is to generate separable programs for each
		//       shader stage, but that requires modifying the glsl to redeclare built-in blocks if necessary.

		refl.ConstantBlocks = cbuffers;
	}

	// update samplers with latest uniform values
	for(int32_t i=0; i < refl.Resources.count; i++)
	{
		if(refl.Resources.elems[i].IsSRV && refl.Resources.elems[i].IsTexture)
			gl.glGetUniformiv(curProg, refl.Resources.elems[i].variableAddress, (GLint *)&refl.Resources.elems[i].bindPoint);
	}

	return &refl;
}
Ejemplo n.º 10
0
void GLReplay::FillCBufferVariables(ResourceId shader, uint32_t cbufSlot, vector<ShaderVariable> &outvars, const vector<byte> &data)
{
	WrappedOpenGL &gl = *m_pDriver;
	
	MakeCurrentReplayContext(&m_ReplayCtx);

	GLuint curProg = 0;
	gl.glGetIntegerv(eGL_CURRENT_PROGRAM, (GLint*)&curProg);

	auto &progDetails = m_pDriver->m_Programs[m_pDriver->GetResourceManager()->GetID(ProgramRes(curProg))];
	auto &shaderDetails = m_pDriver->m_Shaders[shader];

	GLint numUniforms = 0;
	gl.glGetProgramInterfaceiv(curProg, eGL_UNIFORM, eGL_ACTIVE_RESOURCES, &numUniforms);

	const size_t numProps = 6;

	GLenum resProps[numProps] = {
		eGL_REFERENCED_BY_VERTEX_SHADER,

		eGL_TYPE, eGL_NAME_LENGTH, eGL_LOCATION, eGL_BLOCK_INDEX, eGL_ARRAY_SIZE,
	};

	if(shaderDetails.type == eGL_VERTEX_SHADER)          resProps[0] = eGL_REFERENCED_BY_VERTEX_SHADER;
	if(shaderDetails.type == eGL_TESS_CONTROL_SHADER)    resProps[0] = eGL_REFERENCED_BY_TESS_CONTROL_SHADER;
	if(shaderDetails.type == eGL_TESS_EVALUATION_SHADER) resProps[0] = eGL_REFERENCED_BY_TESS_EVALUATION_SHADER;
	if(shaderDetails.type == eGL_GEOMETRY_SHADER)        resProps[0] = eGL_REFERENCED_BY_GEOMETRY_SHADER;
	if(shaderDetails.type == eGL_FRAGMENT_SHADER)        resProps[0] = eGL_REFERENCED_BY_FRAGMENT_SHADER;
	if(shaderDetails.type == eGL_COMPUTE_SHADER)         resProps[0] = eGL_REFERENCED_BY_COMPUTE_SHADER;

	for(GLint u=0; u < numUniforms; u++)
	{
		GLint values[numProps];
		gl.glGetProgramResourceiv(curProg, eGL_UNIFORM, u, numProps, resProps, numProps, NULL, values);

		if(values[0] == GL_FALSE)
			continue;

		// don't look at block uniforms just yet
		if(values[4] != -1)
			continue;

		ShaderVariable var;

		RDCASSERT(values[5] <= 1); // don't handle arrays yet

		if(values[1] == GL_FLOAT_VEC4)
		{
			var.type = eVar_Float;
			var.columns = 4;
			var.rows = 1;

			gl.glGetUniformfv(curProg, values[3], var.value.fv);
		}
		else if(values[1] == GL_FLOAT_VEC3)
		{
			var.type = eVar_Float;
			var.columns = 3;
			var.rows = 1;

			gl.glGetUniformfv(curProg, values[3], var.value.fv);
		}
		else if(values[1] == GL_FLOAT_MAT4)
		{
			var.type = eVar_Float;
			var.columns = 4;
			var.rows = 4;

			gl.glGetUniformfv(curProg, values[3], var.value.fv);
		}
		else
		{
			continue;
		}

		create_array_uninit(var.name, values[2]+1);
		gl.glGetProgramResourceName(curProg, eGL_UNIFORM, u, values[2]+1, NULL, var.name.elems);
		var.name.count--; // trim off trailing null

		outvars.push_back(var);
	}
}
Ejemplo n.º 11
0
bool WrappedOpenGL::Serialise_glCreateShaderProgramv(GLuint program, GLenum type, GLsizei count, const GLchar *const*strings)
{
	SERIALISE_ELEMENT(GLenum, Type, type);
	SERIALISE_ELEMENT(int32_t, Count, count);
	SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(ProgramRes(GetCtx(), program)));

	vector<string> src;

	for(int32_t i=0; i < Count; i++)
	{
		string s;
		if(m_State >= WRITING) s = strings[i];
		m_pSerialiser->SerialiseString("Source", s);
		if(m_State < WRITING) src.push_back(s);
	}

	if(m_State == READING)
	{
		char **sources = new char*[Count];
		
		for(int32_t i=0; i < Count; i++)
			sources[i] = &src[i][0];

		GLuint real = m_Real.glCreateShaderProgramv(Type, Count, sources);
		// we want a separate program that we can mess about with for making overlays
		// and relink without having to worry about restoring the 'real' program state.
		GLuint sepprog = MakeSeparableShaderProgram(m_Real, Type, src, NULL);

		delete[] sources;
		
		GLResource res = ProgramRes(GetCtx(), real);

		ResourceId liveId = m_ResourceManager->RegisterResource(res);
	
		auto &progDetails = m_Programs[liveId];
	
		progDetails.linked = true;
		progDetails.shaders.push_back(liveId);
		progDetails.stageShaders[ShaderIdx(Type)] = liveId;

		auto &shadDetails = m_Shaders[liveId];

		bool pointSizeUsed = false, clipDistanceUsed = false;
		if(Type == eGL_VERTEX_SHADER) CheckVertexOutputUses(src, pointSizeUsed, clipDistanceUsed);

		shadDetails.type = Type;
		shadDetails.sources.swap(src);
		shadDetails.prog = sepprog;
		MakeShaderReflection(m_Real, Type, real, shadDetails.reflection, pointSizeUsed, clipDistanceUsed);

		string s = CompileSPIRV(SPIRVShaderStage(ShaderIdx(shadDetails.type)), shadDetails.sources, shadDetails.spirv);
		if(!shadDetails.spirv.empty())
			DisassembleSPIRV(SPIRVShaderStage(ShaderIdx(shadDetails.type)), shadDetails.spirv, s);

		shadDetails.reflection.Disassembly = s;

		create_array_uninit(shadDetails.reflection.DebugInfo.files, shadDetails.sources.size());
		for(size_t i=0; i < shadDetails.sources.size(); i++)
		{
			shadDetails.reflection.DebugInfo.files[i].first = StringFormat::Fmt("source%u.glsl", (uint32_t)i);
			shadDetails.reflection.DebugInfo.files[i].second = shadDetails.sources[i];
		}

		GetResourceManager()->AddLiveResource(id, res);
	}

	return true;
}
Ejemplo n.º 12
0
bool WrappedOpenGL::Serialise_glCompileShaderIncludeARB(GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length)
{
	SERIALISE_ELEMENT(ResourceId, id, GetResourceManager()->GetID(ShaderRes(GetCtx(), shader)));
	SERIALISE_ELEMENT(int32_t, Count, count);

	vector<string> paths;

	for(int32_t i=0; i < Count; i++)
	{
		string s;
		if(path && path[i])
			s = length > 0 ? string(path[i], path[i] + length[i]) : string(path[i]);
		
		m_pSerialiser->SerialiseString("path", s);

		if(m_State == READING)
			paths.push_back(s);
	}
	
	if(m_State == READING)
	{
		size_t numStrings = paths.size();

		const char **pathstrings = new const char*[numStrings];
		for(size_t i=0; i < numStrings; i++)
			pathstrings[i] = paths[i].c_str();

		ResourceId liveId = GetResourceManager()->GetLiveID(id);

		auto &shadDetails = m_Shaders[liveId];
		
		shadDetails.includepaths.clear();
		shadDetails.includepaths.reserve(Count);

		for(int32_t i=0; i < Count; i++)
			shadDetails.includepaths.push_back(pathstrings[i]);

		bool pointSizeUsed = false, clipDistanceUsed = false;
		if(shadDetails.type == eGL_VERTEX_SHADER) CheckVertexOutputUses(shadDetails.sources, pointSizeUsed, clipDistanceUsed);

		GLuint sepProg = MakeSeparableShaderProgram(m_Real, shadDetails.type, shadDetails.sources, &paths);

		if(sepProg == 0)
		{
			RDCERR("Couldn't make separable program for shader via patching - functionality will be broken.");
		}
		else
		{
			shadDetails.prog = sepProg;
			MakeShaderReflection(m_Real, shadDetails.type, sepProg, shadDetails.reflection, pointSizeUsed, clipDistanceUsed);
			
			string s = CompileSPIRV(SPIRVShaderStage(ShaderIdx(shadDetails.type)), shadDetails.sources, shadDetails.spirv);
			if(!shadDetails.spirv.empty())
				DisassembleSPIRV(SPIRVShaderStage(ShaderIdx(shadDetails.type)), shadDetails.spirv, s);

			shadDetails.reflection.Disassembly = s;

			create_array_uninit(shadDetails.reflection.DebugInfo.files, shadDetails.sources.size());
			for(size_t i=0; i < shadDetails.sources.size(); i++)
			{
				shadDetails.reflection.DebugInfo.files[i].first = StringFormat::Fmt("source%u.glsl", (uint32_t)i);
				shadDetails.reflection.DebugInfo.files[i].second = shadDetails.sources[i];
			}
		}

		m_Real.glCompileShaderIncludeARB(GetResourceManager()->GetLiveResource(id).name, Count, pathstrings, NULL);
		
		delete[] pathstrings;
	}

	return true;
}