Exemplo n.º 1
0
void *Win32CallstackResolver::SendRecvPipeMessage(wstring message)
{
	if(pdblocatePipe == NULL) return NULL;

	DWORD written = 0;
	DWORD msgLen = (DWORD)message.length()*sizeof(wchar_t);
	BOOL success = WriteFile(pdblocatePipe, message.c_str(), msgLen, &written, NULL);

	if(!success || written != msgLen)
		return NULL;

	byte *bufPtr = (byte *)pipeMessageBuf;
	DWORD bufSize = sizeof(pipeMessageBuf);

	do 
	{ 
		DWORD read = 0;
		success = ReadFile(pdblocatePipe, bufPtr, bufSize, &read, NULL);

		RDCDEBUG("'%ls' -> %lu", message.c_str(), read);

		DWORD err = GetLastError();
		if (!success && err != ERROR_MORE_DATA)
		{
			break; 
		}

		bufPtr += read;
		bufSize -= read;
	} while (!success);

	RDCDEBUG("buf: %02x %02x %02x %02x", bufPtr[0], bufPtr[1], bufPtr[2], bufPtr[3]);

	return pipeMessageBuf;
}
Exemplo n.º 2
0
BOOL add_hooks()
{
	wchar_t curFile[512];
	GetModuleFileNameW(NULL, curFile, 512);

	wstring f = strlower(wstring(curFile));

	// bail immediately if we're in a system process. We don't want to hook, log, anything -
	// this instance is being used for a shell extension.
	if(f.find(L"dllhost.exe") != wstring::npos ||
		f.find(L"explorer.exe") != wstring::npos)
	{
#ifndef _RELEASE
		OutputDebugStringA("Hosting renderdoc.dll in shell process\n");
#endif
		return TRUE;
	}

	if(f.find(L"renderdoccmd.exe") != wstring::npos ||
		 f.find(L"renderdocui.exe") != wstring::npos)
	{
		RDCDEBUG("Not creating hooks - in replay app");

		RenderDoc::Inst().SetReplayApp(true);
	
		RenderDoc::Inst().Initialise();

		return true;
	}
	
	RenderDoc::Inst().Initialise();

	RDCLOG("Loading into %ls", curFile);

	const wchar_t *appFilter = NULL; //L"MyApplication";

	if(appFilter != NULL)
	{
		if(wcsstr(curFile, appFilter) == 0)
		{
			RDCDEBUG("Not app I want. Exiting");
			return TRUE;
		}
	}

	LibraryHooks::GetInstance().CreateHooks();

	return TRUE;
}
Exemplo n.º 3
0
void WrappedID3D11DeviceContext::AttemptCapture()
{
	m_State = WRITING_CAPFRAME;

	m_FailureReason = CaptureSucceeded;

	// deferred contexts are initially NOT successful unless empty. That's because we don't have the serialised
	// contents of whatever is in them up until now (could be anything).
	// Only after they have been through a Finish() and then in CAPFRAME mode are they considered
	// successful.
	if(GetType() == D3D11_DEVICE_CONTEXT_DEFERRED)
	{
		RDCDEBUG("Deferred Context %llu Attempting capture - initially %s, %s", GetResourceID(), m_SuccessfulCapture ? "successful" : "unsuccessful", m_EmptyCommandList ? "empty" : "non-empty");

		m_SuccessfulCapture |= m_EmptyCommandList;

		if(m_SuccessfulCapture)
			m_FailureReason = CaptureSucceeded;
		else
			m_FailureReason = CaptureFailed_UncappedCmdlist;
		
		RDCDEBUG("Deferred Context %llu Attempting capture - now %s", GetResourceID(), m_SuccessfulCapture ? "successful" : "unsuccessful");
	}
	else
	{
		RDCDEBUG("Immediate Context %llu Attempting capture", GetResourceID());

		m_SuccessfulCapture = true;
		m_FailureReason = CaptureSucceeded;

		for(auto it=m_DeferredRecords.begin(); it != m_DeferredRecords.end(); ++it)
			(*it)->Delete(m_pDevice->GetResourceManager());
		m_DeferredRecords.clear();

		m_ContextRecord->LockChunks();
		while(m_ContextRecord->HasChunks())
		{
			Chunk *chunk = m_ContextRecord->GetLastChunk();

			SAFE_DELETE(chunk);
			m_ContextRecord->PopChunk();
		}
		m_ContextRecord->UnlockChunks();

		m_ContextRecord->FreeParents(m_pDevice->GetResourceManager());
	}
}
Exemplo n.º 4
0
bool ReplayRenderer::GetDrawcalls(uint32_t frameID, bool includeTimes, rdctype::array<FetchDrawcall> *draws)
{
	if(frameID >= (uint32_t)m_FrameRecord.size() || draws == NULL)
		return false;

	if(includeTimes)
	{
		RDCDEBUG("Timing drawcalls...");

		m_pDevice->TimeDrawcalls(m_FrameRecord[frameID].m_DrawCallList);
	}

	*draws = m_FrameRecord[frameID].m_DrawCallList;
	return true;
}
Exemplo n.º 5
0
void D3D12RenderState::ApplyGraphicsRootElements(ID3D12GraphicsCommandList *cmd) const
{
  for(size_t i = 0; i < graphics.sigelems.size(); i++)
  {
    // just don't set tables that aren't in the descriptor heaps, since it's invalid and can crash
    // and is probably just from stale bindings that aren't going to be used
    if(graphics.sigelems[i].type != eRootTable ||
       std::find(heaps.begin(), heaps.end(), graphics.sigelems[i].id) != heaps.end())
    {
      graphics.sigelems[i].SetToGraphics(GetResourceManager(), cmd, (UINT)i);
    }
    else
    {
      RDCDEBUG("Skipping setting possibly stale graphics root table referring to heap %llu",
               graphics.sigelems[i].id);
    }
  }
}
Exemplo n.º 6
0
// DllMain equivalent
void library_loaded()
{
	string curfile;
	FileIO::GetExecutableFilename(curfile);
	
	if(curfile.find("/renderdoccmd") != string::npos ||
	   curfile.find("/renderdocui") != string::npos ||
	   curfile.find("/qrenderdoc") != string::npos)
	{
		RDCDEBUG("Not creating hooks - in replay app");
		
		RenderDoc::Inst().SetReplayApp(true);
		
		RenderDoc::Inst().Initialise();
		
		return;
	}
	else
	{
		RenderDoc::Inst().Initialise();

		char *logfile = getenv("RENDERDOC_LOGFILE");
		char *opts = getenv("RENDERDOC_CAPTUREOPTS");

		if(opts)
		{
			string optstr = opts;

			CaptureOptions optstruct;
			readCapOpts(optstr.c_str(), &optstruct);

			RenderDoc::Inst().SetCaptureOptions(optstruct);
		}

		if(logfile)
		{
			RenderDoc::Inst().SetLogFile(logfile);
		}
	
		RDCLOG("Loading into %s", curfile.c_str());
	
		LibraryHooks::GetInstance().CreateHooks();
	}
}
Exemplo n.º 7
0
static BOOL add_hooks()
{
    wchar_t curFile[512];
    GetModuleFileNameW(NULL, curFile, 512);

    wstring f = strlower(wstring(curFile));

    // bail immediately if we're in a system process. We don't want to hook, log, anything -
    // this instance is being used for a shell extension.
    if(f.find(L"dllhost.exe") != wstring::npos || f.find(L"explorer.exe") != wstring::npos)
    {
#ifndef _RELEASE
        OutputDebugStringA("Hosting " STRINGIZE(RDOC_DLL_FILE) ".dll in shell process\n");
#endif
        return TRUE;
    }

    if(f.find(CONCAT(L, STRINGIZE(RDOC_DLL_FILE)) L"cmd.exe") != wstring::npos ||
            f.find(CONCAT(L, STRINGIZE(RDOC_DLL_FILE)) L"ui.vshost.exe") != wstring::npos ||
            f.find(L"q" CONCAT(L, STRINGIZE(RDOC_DLL_FILE)) L".exe") != wstring::npos ||
            f.find(CONCAT(L, STRINGIZE(RDOC_DLL_FILE)) L"ui.exe") != wstring::npos)
    {
        RDCDEBUG("Not creating hooks - in replay app");

        RenderDoc::Inst().SetReplayApp(true);

        RenderDoc::Inst().Initialise();

        return true;
    }

    RenderDoc::Inst().Initialise();

    RDCLOG("Loading into %ls", curFile);

    LibraryHooks::GetInstance().CreateHooks();

    return TRUE;
}
Exemplo n.º 8
0
static BOOL add_hooks()
{
  wchar_t curFile[512];
  GetModuleFileNameW(NULL, curFile, 512);

  wstring f = strlower(wstring(curFile));

  // bail immediately if we're in a system process. We don't want to hook, log, anything -
  // this instance is being used for a shell extension.
  if(f.find(L"dllhost.exe") != wstring::npos || f.find(L"explorer.exe") != wstring::npos)
  {
#ifndef _RELEASE
    OutputDebugStringA("Hosting " STRINGIZE(RDOC_DLL_FILE) ".dll in shell process\n");
#endif
    return TRUE;
  }

  // search for an exported symbol with this name, typically renderdoc__replay__marker
  if(HOOKS_IDENTIFY(STRINGIZE(RDOC_DLL_FILE) "__replay__marker"))
  {
    RDCDEBUG("Not creating hooks - in replay app");

    RenderDoc::Inst().SetReplayApp(true);

    RenderDoc::Inst().Initialise();

    return true;
  }

  RenderDoc::Inst().Initialise();

  RDCLOG("Loading into %ls", curFile);

  LibraryHooks::GetInstance().CreateHooks();

  return TRUE;
}
Exemplo n.º 9
0
void *dlopen(const char *filename, int flag)
{
	SCOPED_LOCK(libLock);
	if(realdlopen == NULL) realdlopen = (DLOPENPROC)dlsym(RTLD_NEXT, "dlopen");

	void *ret = realdlopen(filename, flag);

	if(filename && ret)
	{
		for(auto it = libraryHooks.begin(); it != libraryHooks.end(); ++it)
		{
			if(strstr(filename, it->first.c_str()))
			{
				RDCDEBUG("Redirecting dlopen to ourselves for %s", filename);

				it->second(ret);

				ret = realdlopen("librenderdoc.so", flag);
			}
		}
	}

	return ret;
}
Exemplo n.º 10
0
GLXContext glXCreateContextAttribsARB(Display *dpy, GLXFBConfig config, GLXContext shareList, Bool direct, const int *attribList)
{
	const int *attribs = attribList;
	vector<int> attribVec;

	// modify attribs to our liking
	{
		bool flagsNext = false;
		bool flagsFound = false;
		const int *a = attribList;
		while(*a)
		{
			int val = *a;

			if(flagsNext)
			{
				flagsNext = false;

				if(RenderDoc::Inst().GetCaptureOptions().DebugDeviceMode)
					val |= GLX_CONTEXT_DEBUG_BIT_ARB;
				else
					val &= ~GLX_CONTEXT_DEBUG_BIT_ARB;

				// remove NO_ERROR bit
				val &= ~GL_CONTEXT_FLAG_NO_ERROR_BIT_KHR;
			}

			if(val == GLX_CONTEXT_FLAGS_ARB)
			{
				flagsNext = true;
				flagsFound = true;
			}

			attribVec.push_back(val);

			a++;
		}

		if(!flagsFound && RenderDoc::Inst().GetCaptureOptions().DebugDeviceMode)
		{
			attribVec.push_back(GLX_CONTEXT_FLAGS_ARB);
			attribVec.push_back(GLX_CONTEXT_DEBUG_BIT_ARB);
		}

		attribVec.push_back(0);

		attribs = &attribVec[0];
	}

	RDCDEBUG("glXCreateContextAttribsARB:");

	bool core = false;

	int *a = (int *)attribs;
	while(*a)
	{
		RDCDEBUG("%x: %d", a[0], a[1]);
		a += 2;

		if(a[0] == GLX_CONTEXT_PROFILE_MASK_ARB)
			core = (a[1] & GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
	}

	GLXContext ret = OpenGLHook::glhooks.glXCreateContextAttribsARB_real(dpy, config, shareList, direct, attribs);

	XVisualInfo *vis = OpenGLHook::glhooks.glXGetVisualFromFBConfig_real(dpy, config);	
	
	GLInitParams init;
	
	init.width = 0;
	init.height = 0;
	
	int value = 0;
	
	Keyboard::CloneDisplay(dpy);
	
	OpenGLHook::glhooks.glXGetConfig_real(dpy, vis, GLX_BUFFER_SIZE, &value); init.colorBits = value;
	OpenGLHook::glhooks.glXGetConfig_real(dpy, vis, GLX_DEPTH_SIZE, &value); init.depthBits = value;
	OpenGLHook::glhooks.glXGetConfig_real(dpy, vis, GLX_STENCIL_SIZE, &value); init.stencilBits = value;
	value = 1; // default to srgb
	OpenGLHook::glhooks.glXGetConfig_real(dpy, vis, GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB, &value); init.isSRGB = value;
	value = 1;
	OpenGLHook::glhooks.glXGetConfig_real(dpy, vis, GLX_SAMPLES_ARB, &value); init.isSRGB = RDCMAX(1, value);

	XFree(vis);
	
	GLWindowingData data;
	data.dpy = dpy;
	data.wnd = (GLXDrawable)NULL;
	data.ctx = ret;

	OpenGLHook::glhooks.GetDriver()->CreateContext(data, shareList, init, core, true);

	return ret;
}
Exemplo n.º 11
0
MemoryAllocation WrappedVulkan::AllocateMemoryForResource(bool buffer, VkMemoryRequirements mrq,
                                                          MemoryScope scope, MemoryType type)
{
  MemoryAllocation ret;
  ret.scope = scope;
  ret.type = type;
  ret.buffer = buffer;
  ret.size = AlignUp(mrq.size, mrq.alignment);

  RDCDEBUG("Allocating 0x%llx with alignment 0x%llx in 0x%x for a %s (%s in %s)", ret.size,
           mrq.alignment, mrq.memoryTypeBits, buffer ? "buffer" : "image", ToStr(type).c_str(),
           ToStr(scope).c_str());

  std::vector<MemoryAllocation> &blockList = m_MemoryBlocks[(size_t)scope];

  // first try to find a match
  int i = 0;
  for(MemoryAllocation &block : blockList)
  {
    RDCDEBUG(
        "Considering block %d: memory type %u and type %s. Total size 0x%llx, current offset "
        "0x%llx, last alloc was %s",
        i, block.memoryTypeIndex, ToStr(block.type).c_str(), block.size, block.offs,
        block.buffer ? "buffer" : "image");
    i++;

    // skip this block if it's not the memory type we want
    if(ret.type != block.type || (mrq.memoryTypeBits & (1 << block.memoryTypeIndex)) == 0)
    {
      RDCDEBUG("block type %d or memory type %d is incompatible", block.type, block.memoryTypeIndex);
      continue;
    }

    // offs is where we can put our next sub-allocation
    VkDeviceSize offs = block.offs;

    // if we are on a buffer/image, account for any alignment we might have to do
    if(ret.buffer != block.buffer)
      offs = AlignUp(offs, m_PhysicalDeviceData.props.limits.bufferImageGranularity);

    // align as required by the resource
    offs = AlignUp(offs, mrq.alignment);

    if(offs > block.size)
    {
      RDCDEBUG("Next offset 0x%llx would be off the end of the memory (size 0x%llx).", offs,
               block.size);
      continue;
    }

    VkDeviceSize avail = block.size - offs;

    RDCDEBUG("At next offset 0x%llx, there's 0x%llx bytes available for 0x%llx bytes requested",
             offs, avail, ret.size);

    // if the allocation will fit, we've found our candidate.
    if(ret.size <= avail)
    {
      // update the block offset and buffer/image bit
      block.offs = offs + ret.size;
      block.buffer = ret.buffer;

      // update our return value
      ret.offs = offs;
      ret.mem = block.mem;

      RDCDEBUG("Allocating using this block: 0x%llx -> 0x%llx", ret.offs, block.offs);

      // stop searching
      break;
    }
  }

  if(ret.mem == VK_NULL_HANDLE)
  {
    RDCDEBUG("No available block found - allocating new block");

    VkDeviceSize &allocSize = m_MemoryBlockSize[(size_t)scope];

    // we start allocating 32M, then increment each time we need a new block.
    switch(allocSize)
    {
      case 0: allocSize = 32; break;
      case 32: allocSize = 64; break;
      case 64: allocSize = 128; break;
      case 128:
      case 256: allocSize = 256; break;
      default:
        RDCDEBUG("Unexpected previous allocation size 0x%llx bytes, allocating 256MB", allocSize);
        allocSize = 256;
        break;
    }

    uint32_t memoryTypeIndex = 0;

    switch(ret.type)
    {
      case MemoryType::Upload: memoryTypeIndex = GetUploadMemoryIndex(mrq.memoryTypeBits); break;
      case MemoryType::GPULocal:
        memoryTypeIndex = GetGPULocalMemoryIndex(mrq.memoryTypeBits);
        break;
      case MemoryType::Readback:
        memoryTypeIndex = GetReadbackMemoryIndex(mrq.memoryTypeBits);
        break;
    }

    VkMemoryAllocateInfo info = {
        VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, NULL, allocSize * 1024 * 1024, memoryTypeIndex,
    };

    if(ret.size > info.allocationSize)
    {
      // if we get an over-sized allocation, first try to immediately jump to the largest block
      // size.
      allocSize = 256;
      info.allocationSize = allocSize * 1024 * 1024;

      // if it's still over-sized, just allocate precisely enough and give it a dedicated allocation
      if(ret.size > info.allocationSize)
      {
        RDCDEBUG("Over-sized allocation for 0x%llx bytes", ret.size);
        info.allocationSize = ret.size;
      }
    }

    RDCDEBUG("Creating new allocation of 0x%llx bytes", info.allocationSize);

    MemoryAllocation chunk;
    chunk.buffer = ret.buffer;
    chunk.memoryTypeIndex = memoryTypeIndex;
    chunk.scope = scope;
    chunk.type = type;
    chunk.size = info.allocationSize;

    // the offset starts immediately after this allocation
    chunk.offs = ret.size;

    VkDevice d = GetDev();

    // do the actual allocation
    VkResult vkr = ObjDisp(d)->AllocateMemory(Unwrap(d), &info, NULL, &chunk.mem);
    RDCASSERTEQUAL(vkr, VK_SUCCESS);

    GetResourceManager()->WrapResource(Unwrap(d), chunk.mem);

    // push the new chunk
    blockList.push_back(chunk);

    // return the first bytes in the new chunk
    ret.offs = 0;
    ret.mem = chunk.mem;
  }

  return ret;
}
Exemplo n.º 12
0
void WrappedID3D11DeviceContext::ReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial)
{
	m_State = readType;

	m_DoStateVerify = true;

	D3D11ChunkType header = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false);
	RDCASSERT(header == CONTEXT_CAPTURE_HEADER);

	ResourceId id;
	m_pSerialiser->Serialise("context", id);

	WrappedID3D11DeviceContext *context = (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(id);
	
	RDCASSERT(WrappedID3D11DeviceContext::IsAlloc(context) && context == this);

	Serialise_BeginCaptureFrame(!partial);

	m_pSerialiser->PopContext(NULL, header);

	m_CurEvents.clear();
	
	if(m_State == EXECUTING)
	{
		FetchAPIEvent ev = GetEvent(startEventID);
		m_CurEventID = ev.eventID;
		m_pSerialiser->SetOffset(ev.fileOffset);
	}
	else if(m_State == READING)
	{
		m_CurEventID = 1;
	}

	if(m_State == EXECUTING)
	{
		ClearMaps();
		for(size_t i=0; i < m_pDevice->GetNumDeferredContexts(); i++)
		{
			WrappedID3D11DeviceContext *defcontext = m_pDevice->GetDeferredContext(i);
			defcontext->ClearMaps();
		}
	}

	m_pDevice->GetResourceManager()->MarkInFrame(true);

	uint64_t startOffset = m_pSerialiser->GetOffset();

	while(1)
	{
		if(m_State == EXECUTING && m_CurEventID > endEventID)
		{
			// we can just break out if we've done all the events desired.
			break;
		}

		uint64_t offset = m_pSerialiser->GetOffset();

		D3D11ChunkType chunktype = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false);

		ProcessChunk(offset, chunktype, false);
		
		RenderDoc::Inst().SetProgress(FrameEventsRead, float(offset - startOffset)/float(m_pSerialiser->GetSize()));
		
		// for now just abort after capture scope. Really we'd need to support multiple frames
		// but for now this will do.
		if(chunktype == CONTEXT_CAPTURE_FOOTER)
			break;
		
		m_CurEventID++;
	}

	if(m_State == READING)
	{
		m_pDevice->GetFrameRecord().back().drawcallList = m_ParentDrawcall.Bake();
		m_pDevice->GetFrameRecord().back().frameInfo.debugMessages = m_pDevice->GetDebugMessages();

		int initialSkips = 0;

		for(auto it=WrappedID3D11Buffer::m_BufferList.begin(); it != WrappedID3D11Buffer::m_BufferList.end(); ++it)
			m_ResourceUses[it->first];

		for(auto it=WrappedID3D11Texture1D::m_TextureList.begin(); it != WrappedID3D11Texture1D::m_TextureList.end(); ++it)
			m_ResourceUses[it->first];
		for(auto it=WrappedID3D11Texture2D::m_TextureList.begin(); it != WrappedID3D11Texture2D::m_TextureList.end(); ++it)
			m_ResourceUses[it->first];
		for(auto it=WrappedID3D11Texture3D::m_TextureList.begin(); it != WrappedID3D11Texture3D::m_TextureList.end(); ++it)
			m_ResourceUses[it->first];
		
		// it's easier to remove duplicate usages here than check it as we go.
		// this means if textures are bound in multiple places in the same draw
		// we don't have duplicate uses
		for(auto it = m_ResourceUses.begin(); it != m_ResourceUses.end(); ++it)
		{
			vector<EventUsage> &v = it->second;
			std::sort(v.begin(), v.end());
			v.erase( std::unique(v.begin(), v.end()), v.end() );
			
#if 0
			ResourceId resid = m_pDevice->GetResourceManager()->GetOriginalID(it->first);
			
			if(m_pDevice->GetResourceManager()->GetInitialContents(resid).resource == NULL)
				continue;
			
			// code disabled for now as skipping these initial states
			// doesn't seem to produce any measurable improvement in any case
			// I've checked
			RDCDEBUG("Resource %llu", resid);
			if(v.empty())
			{
				RDCDEBUG("Never used!");
				initialSkips++;
			}
			else
			{
				bool written = false;

				for(auto usit = v.begin(); usit != v.end(); ++usit)
				{
					ResourceUsage u = usit->usage;

					if(u == eUsage_SO ||
						(u >= eUsage_VS_RWResource && u <= eUsage_CS_RWResource) ||
						u == eUsage_DepthStencilTarget || u == eUsage_ColourTarget)
					{
						written = true;
						break;
					}
				}

				if(written)
				{
					RDCDEBUG("Written in frame - needs initial state");
				}
				else
				{
					RDCDEBUG("Never written to in the frame");
					initialSkips++;
				}
			}
#endif
		}

		//RDCDEBUG("Can skip %d initial states.", initialSkips);
	}

	m_pDevice->GetResourceManager()->MarkInFrame(false);

	m_State = READING;

	m_DoStateVerify = false;
}
Exemplo n.º 13
0
ReplayCreateStatus D3D12_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
{
  RDCDEBUG("Creating a D3D12 replay device");

  WrappedIDXGISwapChain3::RegisterD3DDeviceCallback(GetD3D12DeviceIfAlloc);

  HMODULE lib = NULL;
  lib = LoadLibraryA("d3d12.dll");
  if(lib == NULL)
  {
    RDCERR("Failed to load d3d12.dll");
    return eReplayCreate_APIInitFailed;
  }

  lib = LoadLibraryA("dxgi.dll");
  if(lib == NULL)
  {
    RDCERR("Failed to load dxgi.dll");
    return eReplayCreate_APIInitFailed;
  }

  if(GetD3DCompiler() == NULL)
  {
    RDCERR("Failed to load d3dcompiler_??.dll");
    return eReplayCreate_APIInitFailed;
  }

  D3D12InitParams initParams;
  RDCDriver driverFileType = RDC_D3D12;
  string driverName = "D3D12";
  if(logfile)
  {
    auto status = RenderDoc::Inst().FillInitParams(logfile, driverFileType, driverName,
                                                   (RDCInitParams *)&initParams);
    if(status != eReplayCreate_Success)
      return status;
  }

  // initParams.SerialiseVersion is guaranteed to be valid/supported since otherwise the
  // FillInitParams (which calls D3D12InitParams::Serialise) would have failed above, so no need to
  // check it here.

  if(initParams.MinimumFeatureLevel < D3D_FEATURE_LEVEL_11_0)
    initParams.MinimumFeatureLevel = D3D_FEATURE_LEVEL_11_0;

  ID3D12Device *dev = NULL;
  HRESULT hr = RENDERDOC_CreateWrappedD3D12Device(NULL, initParams.MinimumFeatureLevel,
                                                  __uuidof(ID3D12Device), (void **)&dev);

  if(FAILED(hr))
  {
    RDCERR("Couldn't create a d3d12 device :(.");

    return eReplayCreate_APIHardwareUnsupported;
  }

  WrappedID3D12Device *wrappedDev = (WrappedID3D12Device *)dev;
  if(logfile)
    wrappedDev->SetLogFile(logfile);
  wrappedDev->SetLogVersion(initParams.SerialiseVersion);

  RDCLOG("Created device.");
  D3D12Replay *replay = wrappedDev->GetReplay();

  replay->SetProxy(logfile == NULL);

  *driver = (IReplayDriver *)replay;
  return eReplayCreate_Success;
}
Exemplo n.º 14
0
bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(UINT NumCommandLists,
                                                              ID3D12CommandList *const *ppCommandLists)
{
  SERIALISE_ELEMENT(UINT, numCmds, NumCommandLists);

  vector<ResourceId> cmdIds;
  ID3D12CommandList **cmds = m_State >= WRITING ? NULL : new ID3D12CommandList *[numCmds];

  if(m_State >= WRITING)
  {
    for(UINT i = 0; i < numCmds; i++)
    {
      D3D12ResourceRecord *record = GetRecord(ppCommandLists[i]);
      RDCASSERT(record->bakedCommands);
      if(record->bakedCommands)
        cmdIds.push_back(record->bakedCommands->GetResourceID());
    }
  }

  m_pSerialiser->Serialise("ppCommandLists", cmdIds);

  if(m_State < WRITING)
  {
    for(UINT i = 0; i < numCmds; i++)
    {
      cmds[i] = cmdIds[i] != ResourceId()
                    ? Unwrap(GetResourceManager()->GetLiveAs<ID3D12CommandList>(cmdIds[i]))
                    : NULL;
    }
  }

  const string desc = m_pSerialiser->GetDebugStr();

  D3D12NOTIMP("Serialise_DebugMessages");

  if(m_State == READING)
  {
    m_pReal->ExecuteCommandLists(numCmds, cmds);

    for(uint32_t i = 0; i < numCmds; i++)
    {
      ResourceId cmd = GetResourceManager()->GetLiveID(cmdIds[i]);
      m_pDevice->ApplyBarriers(m_Cmd.m_BakedCmdListInfo[cmd].barriers);
    }

    m_Cmd.AddEvent(EXECUTE_CMD_LISTS, desc);

    // we're adding multiple events, need to increment ourselves
    m_Cmd.m_RootEventID++;

    string basename = "ExecuteCommandLists(" + ToStr::Get(numCmds) + ")";

    for(uint32_t c = 0; c < numCmds; c++)
    {
      string name = StringFormat::Fmt("=> %s[%u]: ID3D12CommandList(%s)", basename.c_str(), c,
                                      ToStr::Get(cmdIds[c]).c_str());

      // add a fake marker
      FetchDrawcall draw;
      draw.name = name;
      draw.flags |= eDraw_SetMarker;
      m_Cmd.AddEvent(SET_MARKER, name);
      m_Cmd.AddDrawcall(draw, true);
      m_Cmd.m_RootEventID++;

      BakedCmdListInfo &cmdBufInfo = m_Cmd.m_BakedCmdListInfo[cmdIds[c]];

      // insert the baked command list in-line into this list of notes, assigning new event and
      // drawIDs
      m_Cmd.InsertDrawsAndRefreshIDs(cmdBufInfo.draw->children);

      for(size_t e = 0; e < cmdBufInfo.draw->executedCmds.size(); e++)
      {
        vector<uint32_t> &submits =
            m_Cmd.m_Partial[D3D12CommandData::Secondary].cmdListExecs[cmdBufInfo.draw->executedCmds[e]];

        for(size_t s = 0; s < submits.size(); s++)
          submits[s] += m_Cmd.m_RootEventID;
      }

      D3D12NOTIMP("Debug Messages");
      /*
      for(size_t i = 0; i < cmdBufInfo.debugMessages.size(); i++)
      {
        m_DebugMessages.push_back(cmdBufInfo.debugMessages[i]);
        m_DebugMessages.back().eventID += m_RootEventID;
      }
      */

      // only primary command lists can be submitted
      m_Cmd.m_Partial[D3D12CommandData::Primary].cmdListExecs[cmdIds[c]].push_back(
          m_Cmd.m_RootEventID);

      m_Cmd.m_RootEventID += cmdBufInfo.eventCount;
      m_Cmd.m_RootDrawcallID += cmdBufInfo.drawCount;

      name = StringFormat::Fmt("=> %s[%u]: Close(%s)", basename.c_str(), c,
                               ToStr::Get(cmdIds[c]).c_str());
      draw.name = name;
      m_Cmd.AddEvent(SET_MARKER, name);
      m_Cmd.AddDrawcall(draw, true);
      m_Cmd.m_RootEventID++;
    }

    // account for the outer loop thinking we've added one event and incrementing,
    // since we've done all the handling ourselves this will be off by one.
    m_Cmd.m_RootEventID--;
  }
  else if(m_State == EXECUTING)
  {
    // account for the queue submit event
    m_Cmd.m_RootEventID++;

    uint32_t startEID = m_Cmd.m_RootEventID;

    // advance m_CurEventID to match the events added when reading
    for(uint32_t c = 0; c < numCmds; c++)
    {
      // 2 extra for the virtual labels around the command list
      m_Cmd.m_RootEventID += 2 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].eventCount;
      m_Cmd.m_RootDrawcallID += 2 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].drawCount;
    }

    // same accounting for the outer loop as above
    m_Cmd.m_RootEventID--;

    if(numCmds == 0)
    {
      // do nothing, don't bother with the logic below
    }
    else if(m_Cmd.m_LastEventID <= startEID)
    {
#ifdef VERBOSE_PARTIAL_REPLAY
      RDCDEBUG("Queue Submit no replay %u == %u", m_Cmd.m_LastEventID, startEID);
#endif
    }
    else if(m_Cmd.m_DrawcallCallback && m_Cmd.m_DrawcallCallback->RecordAllCmds())
    {
#ifdef VERBOSE_PARTIAL_REPLAY
      RDCDEBUG("Queue Submit re-recording from %u", m_Cmd.m_RootEventID);
#endif

      vector<ID3D12CommandList *> rerecordedCmds;

      for(uint32_t c = 0; c < numCmds; c++)
      {
        ID3D12CommandList *cmd = m_Cmd.RerecordCmdList(cmdIds[c]);
        ResourceId rerecord = GetResID(cmd);
#ifdef VERBOSE_PARTIAL_REPLAY
        RDCDEBUG("Queue Submit fully re-recorded replay of %llu, using %llu", cmdIds[c], rerecord);
#endif
        rerecordedCmds.push_back(Unwrap(cmd));

        m_pDevice->ApplyBarriers(m_Cmd.m_BakedCmdListInfo[rerecord].barriers);
      }

      m_pReal->ExecuteCommandLists((UINT)rerecordedCmds.size(), &rerecordedCmds[0]);
    }
    else if(m_Cmd.m_LastEventID > startEID && m_Cmd.m_LastEventID < m_Cmd.m_RootEventID)
    {
#ifdef VERBOSE_PARTIAL_REPLAY
      RDCDEBUG("Queue Submit partial replay %u < %u", m_Cmd.m_LastEventID, m_Cmd.m_RootEventID);
#endif

      uint32_t eid = startEID;

      vector<ResourceId> trimmedCmdIds;
      vector<ID3D12CommandList *> trimmedCmds;

      for(uint32_t c = 0; c < numCmds; c++)
      {
        // account for the virtual label at the start of the events here
        // so it matches up to baseEvent
        eid++;

        uint32_t end = eid + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].eventCount;

        if(eid == m_Cmd.m_Partial[D3D12CommandData::Primary].baseEvent)
        {
          ID3D12GraphicsCommandList *list =
              m_Cmd.RerecordCmdList(cmdIds[c], D3D12CommandData::Primary);
          ResourceId partial = GetResID(list);
#ifdef VERBOSE_PARTIAL_REPLAY
          RDCDEBUG("Queue Submit partial replay of %llu at %u, using %llu", cmdIds[c], eid, partial);
#endif
          trimmedCmdIds.push_back(partial);
          trimmedCmds.push_back(Unwrap(list));
        }
        else if(m_Cmd.m_LastEventID >= end)
        {
#ifdef VERBOSE_PARTIAL_REPLAY
          RDCDEBUG("Queue Submit full replay %llu", cmdIds[c]);
#endif
          trimmedCmdIds.push_back(cmdIds[c]);
          trimmedCmds.push_back(Unwrap(GetResourceManager()->GetLiveAs<ID3D12CommandList>(cmdIds[c])));
        }
        else
        {
#ifdef VERBOSE_PARTIAL_REPLAY
          RDCDEBUG("Queue not submitting %llu", cmdIds[c]);
#endif
        }

        // 1 extra to account for the virtual end command list label (begin is accounted for
        // above)
        eid += 1 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].eventCount;
      }

      RDCASSERT(trimmedCmds.size() > 0);

      m_pReal->ExecuteCommandLists((UINT)trimmedCmds.size(), &trimmedCmds[0]);

      for(uint32_t i = 0; i < trimmedCmdIds.size(); i++)
      {
        ResourceId cmd = trimmedCmdIds[i];
        m_pDevice->ApplyBarriers(m_Cmd.m_BakedCmdListInfo[cmd].barriers);
      }
    }
    else
    {
#ifdef VERBOSE_PARTIAL_REPLAY
      RDCDEBUG("Queue Submit full replay %u >= %u", m_Cmd.m_LastEventID, m_Cmd.m_RootEventID);
#endif

      m_pReal->ExecuteCommandLists(numCmds, cmds);

      for(uint32_t i = 0; i < numCmds; i++)
      {
        ResourceId cmd = GetResourceManager()->GetLiveID(cmdIds[i]);
        m_pDevice->ApplyBarriers(m_Cmd.m_BakedCmdListInfo[cmd].barriers);
      }
    }
  }

  SAFE_DELETE_ARRAY(cmds);

  return true;
}
Exemplo n.º 15
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);

					RDCDEBUG("Got a no-op");
					msg->Type = eRemoteMsg_Noop;
					return;
				}
				else if(type == ePacket_Busy)
				{
					wstring existingClient;
					ser->Serialise("", existingClient);

					SAFE_DELETE(ser);
					
					SAFE_DELETE(m_Socket);

					RDCLOG("Got busy signal: '%ls", 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_NewCapture)
				{
					msg->Type = eRemoteMsg_NewCapture;

					ser->Serialise("", msg->NewCapture.ID);
					ser->Serialise("", msg->NewCapture.timestamp);
					
					wstring path;
					ser->Serialise("", path);
					msg->NewCapture.localpath = path;

					if(!m_Local)
						msg->NewCapture.localpath = L"";
					
					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: %ls", m_API.c_str());
					
					SAFE_DELETE(ser);

					return;
				}
			}

			SAFE_DELETE(ser);

			msg->Type = eRemoteMsg_Noop;
		}
Exemplo n.º 16
0
bool WrappedVulkan::Serialise_vkCreateDevice(
		Serialiser*                                 localSerialiser,
		VkPhysicalDevice                            physicalDevice,
		const VkDeviceCreateInfo*                   pCreateInfo,
    const VkAllocationCallbacks*                pAllocator,
		VkDevice*                                   pDevice)
{
	SERIALISE_ELEMENT(ResourceId, physId, GetResID(physicalDevice));
	SERIALISE_ELEMENT(VkDeviceCreateInfo, serCreateInfo, *pCreateInfo);
	SERIALISE_ELEMENT(ResourceId, devId, GetResID(*pDevice));

	if(m_State == READING)
	{
		// we must make any modifications locally, so the free of pointers
		// in the serialised VkDeviceCreateInfo don't double-free
		VkDeviceCreateInfo createInfo = serCreateInfo;
		
		std::vector<string> Extensions;
		for(uint32_t i=0; i < createInfo.enabledExtensionCount; i++)
		{
			// don't include the debug marker extension
			if(strcmp(createInfo.ppEnabledExtensionNames[i], VK_EXT_DEBUG_MARKER_EXTENSION_NAME))
				Extensions.push_back(createInfo.ppEnabledExtensionNames[i]);
		}

		std::vector<string> Layers;
		for(uint32_t i=0; i < createInfo.enabledLayerCount; i++)
			Layers.push_back(createInfo.ppEnabledLayerNames[i]);

		StripUnwantedLayers(Layers);

		AddRequiredExtensions(false, Extensions);
		
#if defined(FORCE_VALIDATION_LAYERS)
		Layers.push_back("VK_LAYER_LUNARG_standard_validation");
#endif

		createInfo.enabledLayerCount = (uint32_t)Layers.size();

		const char **layerArray = NULL;
		if(!Layers.empty())
		{
			layerArray = new const char *[createInfo.enabledLayerCount];
			
			for(uint32_t i=0; i < createInfo.enabledLayerCount; i++)
				layerArray[i] = Layers[i].c_str();

			createInfo.ppEnabledLayerNames = layerArray;
		}

		createInfo.enabledExtensionCount = (uint32_t)Extensions.size();

		const char **extArray = NULL;
		if(!Extensions.empty())
		{
			extArray = new const char *[createInfo.enabledExtensionCount];
			
			for(uint32_t i=0; i < createInfo.enabledExtensionCount; i++)
				extArray[i] = Extensions[i].c_str();

			createInfo.ppEnabledExtensionNames = extArray;
		}

		physicalDevice = GetResourceManager()->GetLiveHandle<VkPhysicalDevice>(physId);

		VkDevice device;

		uint32_t qCount = 0;
		ObjDisp(physicalDevice)->GetPhysicalDeviceQueueFamilyProperties(Unwrap(physicalDevice), &qCount, NULL);

		VkQueueFamilyProperties *props = new VkQueueFamilyProperties[qCount];
		ObjDisp(physicalDevice)->GetPhysicalDeviceQueueFamilyProperties(Unwrap(physicalDevice), &qCount, props);

		bool found = false;
		uint32_t qFamilyIdx = 0;
		VkQueueFlags search = (VK_QUEUE_GRAPHICS_BIT);

		// for queue priorities, if we need it
		float one = 1.0f;

		// if we need to change the requested queues, it will point to this
		VkDeviceQueueCreateInfo *modQueues = NULL;

		for(uint32_t i=0; i < createInfo.queueCreateInfoCount; i++)
		{
			uint32_t idx = createInfo.pQueueCreateInfos[i].queueFamilyIndex;
			RDCASSERT(idx < qCount);

			// this requested queue is one we can use too
			if((props[idx].queueFlags & search) == search && createInfo.pQueueCreateInfos[i].queueCount > 0)
			{
				qFamilyIdx = idx;
				found = true;
				break;
			}
		}

		// if we didn't find it, search for which queue family we should add a request for
		if(!found)
		{
			RDCDEBUG("App didn't request a queue family we can use - adding our own");

			for(uint32_t i=0; i < qCount; i++)
			{
				if((props[i].queueFlags & search) == search)
				{
					qFamilyIdx = i;
					found = true;
					break;
				}
			}

			if(!found)
			{
				SAFE_DELETE_ARRAY(props);
				RDCERR("Can't add a queue with required properties for RenderDoc! Unsupported configuration");
			}
			else
			{
				// we found the queue family, add it
				modQueues = new VkDeviceQueueCreateInfo[createInfo.queueCreateInfoCount + 1];
				for(uint32_t i=0; i < createInfo.queueCreateInfoCount; i++)
					modQueues[i] = createInfo.pQueueCreateInfos[i];

				modQueues[createInfo.queueCreateInfoCount].queueFamilyIndex = qFamilyIdx;
				modQueues[createInfo.queueCreateInfoCount].queueCount = 1;
				modQueues[createInfo.queueCreateInfoCount].pQueuePriorities = &one;

				createInfo.pQueueCreateInfos = modQueues;
				createInfo.queueCreateInfoCount++;
			}
		}
		
		SAFE_DELETE_ARRAY(props);

		VkPhysicalDeviceFeatures enabledFeatures = {0};
		if(createInfo.pEnabledFeatures != NULL) enabledFeatures = *createInfo.pEnabledFeatures;
		createInfo.pEnabledFeatures = &enabledFeatures;

		VkPhysicalDeviceFeatures availFeatures = {0};
		ObjDisp(physicalDevice)->GetPhysicalDeviceFeatures(Unwrap(physicalDevice), &availFeatures);

		if(availFeatures.fillModeNonSolid)
			enabledFeatures.fillModeNonSolid = true;
		else
			RDCWARN("fillModeNonSolid = false, wireframe overlay will be solid");
		
		if(availFeatures.robustBufferAccess)
			enabledFeatures.robustBufferAccess = true;
		else
			RDCWARN("robustBufferAccess = false, out of bounds access due to bugs in application or RenderDoc may cause crashes");

		if(availFeatures.vertexPipelineStoresAndAtomics)
			enabledFeatures.vertexPipelineStoresAndAtomics = true;
		else
			RDCWARN("vertexPipelineStoresAndAtomics = false, output mesh data will not be available");

		uint32_t numExts = 0;

		VkResult vkr = ObjDisp(physicalDevice)->EnumerateDeviceExtensionProperties(Unwrap(physicalDevice), NULL, &numExts, NULL);
		RDCASSERTEQUAL(vkr, VK_SUCCESS);

		VkExtensionProperties *exts = new VkExtensionProperties[numExts];

		vkr = ObjDisp(physicalDevice)->EnumerateDeviceExtensionProperties(Unwrap(physicalDevice), NULL, &numExts, exts);
		RDCASSERTEQUAL(vkr, VK_SUCCESS);

		for(uint32_t i=0; i < numExts; i++)
			RDCLOG("Ext %u: %s (%u)", i, exts[i].extensionName, exts[i].specVersion);

		SAFE_DELETE_ARRAY(exts);

		// PORTABILITY check that extensions and layers supported in capture (from createInfo) are supported in replay

		vkr = GetDeviceDispatchTable(NULL)->CreateDevice(Unwrap(physicalDevice), &createInfo, NULL, &device);
		RDCASSERTEQUAL(vkr, VK_SUCCESS);

		GetResourceManager()->WrapResource(device, device);
		GetResourceManager()->AddLiveResource(devId, device);
		
		InitDeviceReplayTables(Unwrap(device));

		RDCASSERT(m_Device == VK_NULL_HANDLE); // MULTIDEVICE
		
		m_PhysicalDevice = physicalDevice;
		m_Device = device;

		m_QueueFamilyIdx = qFamilyIdx;

		if(m_InternalCmds.cmdpool == VK_NULL_HANDLE)
		{
			VkCommandPoolCreateInfo poolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, NULL, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, qFamilyIdx };
			vkr = ObjDisp(device)->CreateCommandPool(Unwrap(device), &poolInfo, NULL, &m_InternalCmds.cmdpool);
			RDCASSERTEQUAL(vkr, VK_SUCCESS);

			GetResourceManager()->WrapResource(Unwrap(device), m_InternalCmds.cmdpool);
		}
		
		ObjDisp(physicalDevice)->GetPhysicalDeviceProperties(Unwrap(physicalDevice), &m_PhysicalDeviceData.props);
		
		ObjDisp(physicalDevice)->GetPhysicalDeviceMemoryProperties(Unwrap(physicalDevice), &m_PhysicalDeviceData.memProps);

		ObjDisp(physicalDevice)->GetPhysicalDeviceFeatures(Unwrap(physicalDevice), &m_PhysicalDeviceData.features);

		for(int i=VK_FORMAT_BEGIN_RANGE+1; i < VK_FORMAT_END_RANGE; i++)
			ObjDisp(physicalDevice)->GetPhysicalDeviceFormatProperties(Unwrap(physicalDevice), VkFormat(i), &m_PhysicalDeviceData.fmtprops[i]);

		m_PhysicalDeviceData.readbackMemIndex = m_PhysicalDeviceData.GetMemoryIndex(~0U, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 0);
		m_PhysicalDeviceData.uploadMemIndex = m_PhysicalDeviceData.GetMemoryIndex(~0U, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 0);
		m_PhysicalDeviceData.GPULocalMemIndex = m_PhysicalDeviceData.GetMemoryIndex(~0U, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);

		for(size_t i=0; i < m_PhysicalDevices.size(); i++)
		{
			if(physicalDevice == m_PhysicalDevices[i])
			{
				m_PhysicalDeviceData.memIdxMap = m_MemIdxMaps[i];
				break;
			}
		}

		m_DebugManager = new VulkanDebugManager(this, device);

		SAFE_DELETE_ARRAY(modQueues);
		SAFE_DELETE_ARRAY(layerArray);
		SAFE_DELETE_ARRAY(extArray);
	}

	return true;
}
Exemplo n.º 17
0
ReplayCreateStatus GL_CreateReplayDevice(const wchar_t *logfile, IReplayDriver **driver)
{
	RDCDEBUG("Creating an OpenGL replay device");

	if(glXCreateContextAttribsProc == NULL)
	{
		glXGetFuncProc = (PFNGLXGETPROCADDRESSPROC)dlsym(RTLD_NEXT, "glXGetProcAddress");
		glXDestroyCtxProc = (PFNGLXDESTROYCONTEXTPROC)dlsym(RTLD_NEXT, "glXDestroyContext");
		glXSwapProc = (PFNGLXSWAPBUFFERSPROC)dlsym(RTLD_NEXT, "glXSwapBuffers");
		glXChooseFBConfigProc = (PFNGLXCHOOSEFBCONFIGPROC)dlsym(RTLD_NEXT, "glXChooseFBConfig");
		glXCreatePbufferProc = (PFNGLXCREATEPBUFFERPROC)dlsym(RTLD_NEXT, "glXCreatePbuffer");
		glXDestroyPbufferProc = (PFNGLXDESTROYPBUFFERPROC)dlsym(RTLD_NEXT, "glXDestroyPbuffer");
		glXQueryDrawableProc = (PFNGLXQUERYDRAWABLEPROC)dlsym(RTLD_NEXT, "glXQueryDrawable");

		if(glXGetFuncProc == NULL || glXDestroyCtxProc == NULL ||
			 glXSwapProc == NULL || glXChooseFBConfigProc == NULL ||
			 glXCreatePbufferProc == NULL || glXDestroyPbufferProc == NULL ||
			 glXQueryDrawableProc == NULL)
		{
			RDCERR("Couldn't find required entry points, glXGetProcAddress glXDestroyContext glXSwapBuffers");
			return eReplayCreate_APIInitFailed;
		}

		glXCreateContextAttribsProc = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetFuncProc((const GLubyte*)"glXCreateContextAttribsARB");
		glXMakeContextCurrentProc = (PFNGLXMAKECONTEXTCURRENTPROC)glXGetFuncProc((const GLubyte*)"glXMakeContextCurrent");

		if(glXCreateContextAttribsProc == NULL || glXMakeContextCurrentProc == NULL)
		{
			RDCERR("Couldn't get glx function addresses, glXCreateContextAttribsARB glXMakeContextCurrent");
			return eReplayCreate_APIInitFailed;
		}
	}

	GLInitParams initParams;
	RDCDriver driverType = RDC_OpenGL;
	wstring driverName = L"OpenGL";
	if(logfile)
		RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, (RDCInitParams *)&initParams);

	if(initParams.SerialiseVersion != GLInitParams::GL_SERIALISE_VERSION)
	{
		RDCERR("Incompatible OpenGL serialise version, expected %d got %d", GLInitParams::GL_SERIALISE_VERSION, initParams.SerialiseVersion);
		return eReplayCreate_APIIncompatibleVersion;
	}

	int attribs[64] = {0};
	int i=0;

	attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
	attribs[i++] = 4;
	attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
	attribs[i++] = 3;
	attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
	attribs[i++] = GLX_CONTEXT_DEBUG_BIT_ARB;

	Display *dpy = XOpenDisplay(NULL);

	if(dpy == NULL)
	{
		RDCERR("Couldn't open default X display");
		return eReplayCreate_APIInitFailed;
	}

	// don't need to care about the fb config as we won't be using the default framebuffer (backbuffer)
	static int visAttribs[] = { 0 };
	int numCfgs = 0;
	GLXFBConfig *fbcfg = glXChooseFBConfigProc(dpy, DefaultScreen(dpy), visAttribs, &numCfgs);

	if(fbcfg == NULL)
	{
		XCloseDisplay(dpy);
		RDCERR("Couldn't choose default framebuffer config");
		return eReplayCreate_APIInitFailed;
	}

	GLXContext ctx = glXCreateContextAttribsProc(dpy, fbcfg[0], 0, true, attribs);

	if(ctx == NULL)
	{
		XCloseDisplay(dpy);
		RDCERR("Couldn't create 4.3 context - RenderDoc requires OpenGL 4.3 availability");
		return eReplayCreate_APIHardwareUnsupported;
	}

	// don't care about pbuffer properties for same reason as backbuffer
	int pbAttribs[] = { GLX_PBUFFER_WIDTH, 32, GLX_PBUFFER_HEIGHT, 32, 0 };

	GLXPbuffer pbuffer = glXCreatePbufferProc(dpy, fbcfg[0], pbAttribs);

	XFree(fbcfg);

	Bool res = glXMakeContextCurrentProc(dpy, pbuffer, pbuffer, ctx);

	if(!res)
	{
		glXDestroyPbufferProc(dpy, pbuffer);
		glXDestroyCtxProc(dpy, ctx);
		XCloseDisplay(dpy);
		RDCERR("Couldn't make pbuffer & context current");
		return eReplayCreate_APIInitFailed;
	}

	WrappedOpenGL *gl = new WrappedOpenGL(logfile, GetRealFunctions());
	gl->Initialise(initParams);

	RDCLOG("Created device.");
	GLReplay *replay = gl->GetReplay();
	replay->SetProxy(logfile == NULL);
	GLWindowingData data;
	data.dpy = dpy;
	data.ctx = ctx;
	data.wnd = pbuffer;
	replay->SetReplayData(data);

	*driver = (IReplayDriver *)replay;
	return eReplayCreate_Success;
}
Exemplo n.º 18
0
bool WrappedVulkan::Serialise_vkQueueSubmit(Serialiser *localSerialiser, VkQueue queue,
                                            uint32_t submitCount, const VkSubmitInfo *pSubmits,
                                            VkFence fence)
{
  SERIALISE_ELEMENT(ResourceId, queueId, GetResID(queue));
  SERIALISE_ELEMENT(ResourceId, fenceId, fence != VK_NULL_HANDLE ? GetResID(fence) : ResourceId());

  SERIALISE_ELEMENT(uint32_t, numCmds, pSubmits->commandBufferCount);

  vector<ResourceId> cmdIds;
  VkCommandBuffer *cmds = m_State >= WRITING ? NULL : new VkCommandBuffer[numCmds];
  for(uint32_t i = 0; i < numCmds; i++)
  {
    ResourceId bakedId;

    if(m_State >= WRITING)
    {
      VkResourceRecord *record = GetRecord(pSubmits->pCommandBuffers[i]);
      RDCASSERT(record->bakedCommands);
      if(record->bakedCommands)
        bakedId = record->bakedCommands->GetResourceID();
    }

    SERIALISE_ELEMENT(ResourceId, id, bakedId);

    if(m_State < WRITING)
    {
      cmdIds.push_back(id);

      cmds[i] = id != ResourceId() ? Unwrap(GetResourceManager()->GetLiveHandle<VkCommandBuffer>(id))
                                   : NULL;
    }
  }

  if(m_State < WRITING)
  {
    queue = GetResourceManager()->GetLiveHandle<VkQueue>(queueId);
    if(fenceId != ResourceId())
      fence = GetResourceManager()->GetLiveHandle<VkFence>(fenceId);
    else
      fence = VK_NULL_HANDLE;
  }

  // we don't serialise semaphores at all, just whether we waited on any.
  // For waiting semaphores, since we don't track state we have to just conservatively
  // wait for queue idle. Since we do that, there's equally no point in signalling semaphores
  SERIALISE_ELEMENT(uint32_t, numWaitSems, pSubmits->waitSemaphoreCount);

  if(m_State < WRITING && numWaitSems > 0)
    ObjDisp(queue)->QueueWaitIdle(Unwrap(queue));

  VkSubmitInfo submitInfo = {
      VK_STRUCTURE_TYPE_SUBMIT_INFO,
      NULL,
      0,
      NULL,
      NULL,    // wait semaphores
      numCmds,
      cmds,    // command buffers
      0,
      NULL,    // signal semaphores
  };

  const string desc = localSerialiser->GetDebugStr();

  Serialise_DebugMessages(localSerialiser, true);

  if(m_State == READING)
  {
    // don't submit the fence, since we have nothing to wait on it being signalled, and we might
    // not have it correctly in the unsignalled state.
    ObjDisp(queue)->QueueSubmit(Unwrap(queue), 1, &submitInfo, VK_NULL_HANDLE);

    for(uint32_t i = 0; i < numCmds; i++)
    {
      ResourceId cmd = GetResourceManager()->GetLiveID(cmdIds[i]);
      GetResourceManager()->ApplyBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts);
    }

    AddEvent(QUEUE_SUBMIT, desc);

    // we're adding multiple events, need to increment ourselves
    m_RootEventID++;

    string basename = "vkQueueSubmit(" + ToStr::Get(numCmds) + ")";

    for(uint32_t c = 0; c < numCmds; c++)
    {
      string name = StringFormat::Fmt("=> %s[%u]: vkBeginCommandBuffer(%s)", basename.c_str(), c,
                                      ToStr::Get(cmdIds[c]).c_str());

      // add a fake marker
      FetchDrawcall draw;
      draw.name = name;
      draw.flags |= eDraw_SetMarker;
      AddEvent(SET_MARKER, name);
      AddDrawcall(draw, true);
      m_RootEventID++;

      BakedCmdBufferInfo &cmdBufInfo = m_BakedCmdBufferInfo[cmdIds[c]];

      // insert the baked command buffer in-line into this list of notes, assigning new event and
      // drawIDs
      InsertDrawsAndRefreshIDs(cmdBufInfo.draw->children);

      for(size_t e = 0; e < cmdBufInfo.draw->executedCmds.size(); e++)
      {
        vector<uint32_t> &submits =
            m_Partial[Secondary].cmdBufferSubmits[cmdBufInfo.draw->executedCmds[e]];

        for(size_t s = 0; s < submits.size(); s++)
          submits[s] += m_RootEventID;
      }

      for(size_t i = 0; i < cmdBufInfo.debugMessages.size(); i++)
      {
        m_DebugMessages.push_back(cmdBufInfo.debugMessages[i]);
        m_DebugMessages.back().eventID += m_RootEventID;
      }

      // only primary command buffers can be submitted
      m_Partial[Primary].cmdBufferSubmits[cmdIds[c]].push_back(m_RootEventID);

      m_RootEventID += cmdBufInfo.eventCount;
      m_RootDrawcallID += cmdBufInfo.drawCount;

      name = StringFormat::Fmt("=> %s[%u]: vkEndCommandBuffer(%s)", basename.c_str(), c,
                               ToStr::Get(cmdIds[c]).c_str());
      draw.name = name;
      AddEvent(SET_MARKER, name);
      AddDrawcall(draw, true);
      m_RootEventID++;
    }

    // account for the outer loop thinking we've added one event and incrementing,
    // since we've done all the handling ourselves this will be off by one.
    m_RootEventID--;
  }
  else if(m_State == EXECUTING)
  {
    // account for the queue submit event
    m_RootEventID++;

    uint32_t startEID = m_RootEventID;

    // advance m_CurEventID to match the events added when reading
    for(uint32_t c = 0; c < numCmds; c++)
    {
      // 2 extra for the virtual labels around the command buffer
      m_RootEventID += 2 + m_BakedCmdBufferInfo[cmdIds[c]].eventCount;
      m_RootDrawcallID += 2 + m_BakedCmdBufferInfo[cmdIds[c]].drawCount;
    }

    // same accounting for the outer loop as above
    m_RootEventID--;

    if(numCmds == 0)
    {
      // do nothing, don't bother with the logic below
    }
    else if(m_LastEventID <= startEID)
    {
#ifdef VERBOSE_PARTIAL_REPLAY
      RDCDEBUG("Queue Submit no replay %u == %u", m_LastEventID, startEID);
#endif
    }
    else if(m_DrawcallCallback && m_DrawcallCallback->RecordAllCmds())
    {
#ifdef VERBOSE_PARTIAL_REPLAY
      RDCDEBUG("Queue Submit re-recording from %u", m_RootEventID);
#endif

      vector<VkCommandBuffer> rerecordedCmds;

      for(uint32_t c = 0; c < numCmds; c++)
      {
        VkCommandBuffer cmd = RerecordCmdBuf(cmdIds[c]);
        ResourceId rerecord = GetResID(cmd);
#ifdef VERBOSE_PARTIAL_REPLAY
        RDCDEBUG("Queue Submit fully re-recorded replay of %llu, using %llu", cmdIds[c], rerecord);
#endif
        rerecordedCmds.push_back(Unwrap(cmd));

        GetResourceManager()->ApplyBarriers(m_BakedCmdBufferInfo[rerecord].imgbarriers,
                                            m_ImageLayouts);
      }

      submitInfo.commandBufferCount = (uint32_t)rerecordedCmds.size();
      submitInfo.pCommandBuffers = &rerecordedCmds[0];
      // don't submit the fence, since we have nothing to wait on it being signalled, and we might
      // not have it correctly in the unsignalled state.
      ObjDisp(queue)->QueueSubmit(Unwrap(queue), 1, &submitInfo, VK_NULL_HANDLE);
    }
    else if(m_LastEventID > startEID && m_LastEventID < m_RootEventID)
    {
#ifdef VERBOSE_PARTIAL_REPLAY
      RDCDEBUG("Queue Submit partial replay %u < %u", m_LastEventID, m_RootEventID);
#endif

      uint32_t eid = startEID;

      vector<ResourceId> trimmedCmdIds;
      vector<VkCommandBuffer> trimmedCmds;

      for(uint32_t c = 0; c < numCmds; c++)
      {
        // account for the virtual vkBeginCommandBuffer label at the start of the events here
        // so it matches up to baseEvent
        eid++;

        uint32_t end = eid + m_BakedCmdBufferInfo[cmdIds[c]].eventCount;

        if(eid == m_Partial[Primary].baseEvent)
        {
          ResourceId partial = GetResID(RerecordCmdBuf(cmdIds[c], Primary));
#ifdef VERBOSE_PARTIAL_REPLAY
          RDCDEBUG("Queue Submit partial replay of %llu at %u, using %llu", cmdIds[c], eid, partial);
#endif
          trimmedCmdIds.push_back(partial);
          trimmedCmds.push_back(Unwrap(RerecordCmdBuf(cmdIds[c], Primary)));
        }
        else if(m_LastEventID >= end)
        {
#ifdef VERBOSE_PARTIAL_REPLAY
          RDCDEBUG("Queue Submit full replay %llu", cmdIds[c]);
#endif
          trimmedCmdIds.push_back(cmdIds[c]);
          trimmedCmds.push_back(
              Unwrap(GetResourceManager()->GetLiveHandle<VkCommandBuffer>(cmdIds[c])));
        }
        else
        {
#ifdef VERBOSE_PARTIAL_REPLAY
          RDCDEBUG("Queue not submitting %llu", cmdIds[c]);
#endif
        }

        // 1 extra to account for the virtual end command buffer label (begin is accounted for
        // above)
        eid += 1 + m_BakedCmdBufferInfo[cmdIds[c]].eventCount;
      }

      RDCASSERT(trimmedCmds.size() > 0);

      submitInfo.commandBufferCount = (uint32_t)trimmedCmds.size();
      submitInfo.pCommandBuffers = &trimmedCmds[0];
      // don't submit the fence, since we have nothing to wait on it being signalled, and we might
      // not have it correctly in the unsignalled state.
      ObjDisp(queue)->QueueSubmit(Unwrap(queue), 1, &submitInfo, VK_NULL_HANDLE);

      for(uint32_t i = 0; i < trimmedCmdIds.size(); i++)
      {
        ResourceId cmd = trimmedCmdIds[i];
        GetResourceManager()->ApplyBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts);
      }
    }
    else
    {
#ifdef VERBOSE_PARTIAL_REPLAY
      RDCDEBUG("Queue Submit full replay %u >= %u", m_LastEventID, m_RootEventID);
#endif

      // don't submit the fence, since we have nothing to wait on it being signalled, and we might
      // not have it correctly in the unsignalled state.
      ObjDisp(queue)->QueueSubmit(Unwrap(queue), 1, &submitInfo, VK_NULL_HANDLE);

      for(uint32_t i = 0; i < numCmds; i++)
      {
        ResourceId cmd = GetResourceManager()->GetLiveID(cmdIds[i]);
        GetResourceManager()->ApplyBarriers(m_BakedCmdBufferInfo[cmd].imgbarriers, m_ImageLayouts);
      }
    }
  }

  SAFE_DELETE_ARRAY(cmds);

  return true;
}
Exemplo n.º 19
0
  HRESULT Create_Internal(IUnknown *pAdapter, D3D_FEATURE_LEVEL MinimumFeatureLevel, REFIID riid,
                          void **ppDevice)
  {
    // if we're already inside a wrapped create i.e. this function, then DON'T do anything
    // special. Just grab the trampolined function and call it.
    if(m_InsideCreate)
    {
      PFN_D3D12_CREATE_DEVICE createFunc = NULL;

      // shouldn't ever get in here if we're in the case without hooks but let's be safe.
      if(m_HasHooks)
      {
        createFunc = CreateDevice();
      }
      else
      {
        HMODULE d3d12 = GetModuleHandleA("d3d12.dll");

        if(d3d12)
        {
          createFunc = (PFN_D3D12_CREATE_DEVICE)GetProcAddress(d3d12, "D3D12CreateDevice");
        }
        else
        {
          RDCERR("Something went seriously wrong, d3d12.dll couldn't be loaded!");
          return E_UNEXPECTED;
        }
      }

      return createFunc(pAdapter, MinimumFeatureLevel, riid, ppDevice);
    }

    m_InsideCreate = true;

    if(riid != __uuidof(ID3D12Device))
    {
      RDCERR("Unsupported UUID %s for D3D12CreateDevice", ToStr::Get(riid).c_str());
      return E_NOINTERFACE;
    }

    RDCDEBUG("Call to Create_Internal Feature Level %x", MinimumFeatureLevel,
             ToStr::Get(riid).c_str());

    bool reading = RenderDoc::Inst().IsReplayApp();

    if(reading)
    {
      RDCDEBUG("In replay app");
    }

    const bool EnableDebugLayer =
#if 1    // toggle on/off if you want debug layer during replay
        RenderDoc::Inst().IsReplayApp() ||
#endif
        (m_EnabledHooks && !reading && RenderDoc::Inst().GetCaptureOptions().APIValidation);

    if(EnableDebugLayer)
    {
      PFN_D3D12_GET_DEBUG_INTERFACE getfn = GetDebugInterface();

      if(getfn == NULL)
        getfn = (PFN_D3D12_GET_DEBUG_INTERFACE)GetProcAddress(GetModuleHandleA("d3d12.dll"),
                                                              "D3D12GetDebugInterface");

      if(getfn)
      {
        ID3D12Debug *debug = NULL;
        HRESULT hr = getfn(__uuidof(ID3D12Debug), (void **)&debug);

        if(SUCCEEDED(hr) && debug)
          debug->EnableDebugLayer();
        else
          RDCERR("Couldn't enable debug layer: %x", hr);

        SAFE_RELEASE(debug);
      }
      else
      {
        RDCERR("Couldn't find D3D12GetDebugInterface!");
      }
    }

    RDCDEBUG("Calling real createdevice...");

    PFN_D3D12_CREATE_DEVICE createFunc =
        (PFN_D3D12_CREATE_DEVICE)GetProcAddress(GetModuleHandleA("d3d12.dll"), "D3D12CreateDevice");

    if(createFunc == NULL)
      createFunc = CreateDevice();

    // shouldn't ever get here, we should either have it from procaddress or the trampoline, but
    // let's be safe.
    if(createFunc == NULL)
    {
      RDCERR("Something went seriously wrong with the hooks!");

      m_InsideCreate = false;

      return E_UNEXPECTED;
    }

    HRESULT ret = createFunc(pAdapter, MinimumFeatureLevel, riid, ppDevice);

    RDCDEBUG("Called real createdevice... 0x%08x", ret);

    if(SUCCEEDED(ret) && m_EnabledHooks && ppDevice)
    {
      RDCDEBUG("succeeded and hooking.");

      if(!WrappedID3D12Device::IsAlloc(*ppDevice))
      {
        D3D12InitParams params;
        params.MinimumFeatureLevel = MinimumFeatureLevel;

        ID3D12Device *dev = (ID3D12Device *)*ppDevice;

        WrappedID3D12Device *wrap = new WrappedID3D12Device(dev, &params);

        RDCDEBUG("created wrapped device.");

        *ppDevice = (ID3D12Device *)wrap;
      }
    }
    else if(SUCCEEDED(ret))
    {
      RDCLOG("Created wrapped D3D12 device.");
    }
    else
    {
      RDCDEBUG("failed. 0x%08x", ret);
    }

    m_InsideCreate = false;

    return ret;
  }
Exemplo n.º 20
0
Socket *CreateClientSocket(const wchar_t *host, uint16_t port, int timeoutMS)
{
	char portstr[7] = {0};
	StringFormat::snprintf(portstr, 6, "%d", port);
	
	addrinfo hints;
	RDCEraseEl(hints);
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;


	wstring hostWide = wstring(host);
	string hoststr = narrow(hostWide);

	if(widen(hoststr) != hostWide)
		RDCWARN("Unicode hostname truncated: %S", hostWide.c_str());

	addrinfo *result = NULL;
	getaddrinfo(hoststr.c_str(), portstr, &hints, &result);
	
	for(addrinfo *ptr = result; ptr != NULL; ptr = ptr->ai_next)
	{
		int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

		if(s == -1)
			return NULL;
		
		int flags = fcntl(s, F_GETFL, 0);
		fcntl(s, F_SETFL, flags | O_NONBLOCK);
		
		int result = connect(s, ptr->ai_addr, (int)ptr->ai_addrlen);
		if(result == -1)
		{
			fd_set set;
			FD_ZERO(&set);
			FD_SET(s, &set);

			int err = errno;

			if(err == EWOULDBLOCK)
			{
				timeval timeout;
				timeout.tv_sec = (timeoutMS/1000);
				timeout.tv_usec = (timeoutMS%1000)*1000;
				result = select(0, NULL, &set, NULL, &timeout);

				if(result <= 0)
				{
					RDCDEBUG("connect timed out");
					close(s);
					continue;
				}
				else
				{
					RDCDEBUG("connect before timeout");
				}
			}
			else
			{
				RDCDEBUG("problem other than blocking");
				close(s);
				continue;
			}
		}
		else
		{
			RDCDEBUG("connected immediately");
		}

		int nodelay = 1;
		setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&nodelay, sizeof(nodelay));
		
		return new Socket((ptrdiff_t)s);
	}

	RDCWARN("Failed to connect to %S:%d", host, port);
	return NULL;
}
Exemplo n.º 21
0
void D3D12RenderState::ApplyState(ID3D12GraphicsCommandList *cmd)
{
  if(pipe != ResourceId())
    cmd->SetPipelineState(GetResourceManager()->GetCurrentAs<ID3D12PipelineState>(pipe));

  if(!views.empty())
    cmd->RSSetViewports((UINT)views.size(), &views[0]);

  if(!scissors.empty())
    cmd->RSSetScissorRects((UINT)scissors.size(), &scissors[0]);

  if(topo != D3D_PRIMITIVE_TOPOLOGY_UNDEFINED)
    cmd->IASetPrimitiveTopology(topo);

  cmd->OMSetStencilRef(stencilRef);
  cmd->OMSetBlendFactor(blendFactor);

  if(ibuffer.buf != ResourceId())
  {
    D3D12_INDEX_BUFFER_VIEW ib;

    ID3D12Resource *res = GetResourceManager()->GetCurrentAs<ID3D12Resource>(ibuffer.buf);
    if(res)
      ib.BufferLocation = res->GetGPUVirtualAddress() + ibuffer.offs;
    else
      ib.BufferLocation = 0;

    ib.Format = (ibuffer.bytewidth == 2 ? DXGI_FORMAT_R16_UINT : DXGI_FORMAT_R32_UINT);
    ib.SizeInBytes = ibuffer.size;

    cmd->IASetIndexBuffer(&ib);
  }

  for(size_t i = 0; i < vbuffers.size(); i++)
  {
    D3D12_VERTEX_BUFFER_VIEW vb;

    ID3D12Resource *res = GetResourceManager()->GetCurrentAs<ID3D12Resource>(vbuffers[i].buf);
    if(res)
      vb.BufferLocation = res->GetGPUVirtualAddress() + vbuffers[i].offs;
    else
      vb.BufferLocation = 0;

    vb.StrideInBytes = vbuffers[i].stride;
    vb.SizeInBytes = vbuffers[i].size;

    cmd->IASetVertexBuffers((UINT)i, 1, &vb);
  }

  std::vector<ID3D12DescriptorHeap *> descHeaps;
  descHeaps.resize(heaps.size());

  for(size_t i = 0; i < heaps.size(); i++)
    descHeaps[i] = GetResourceManager()->GetCurrentAs<ID3D12DescriptorHeap>(heaps[i]);

  if(!descHeaps.empty())
    cmd->SetDescriptorHeaps((UINT)descHeaps.size(), &descHeaps[0]);

  if(!rts.empty() || dsv.heap != ResourceId())
  {
    D3D12_CPU_DESCRIPTOR_HANDLE rtHandles[8];
    D3D12_CPU_DESCRIPTOR_HANDLE dsvHandle = CPUHandleFromPortableHandle(GetResourceManager(), dsv);

    UINT numActualHandles = rtSingle ? 1 : (UINT)rts.size();

    for(UINT i = 0; i < numActualHandles; i++)
      rtHandles[i] = CPUHandleFromPortableHandle(GetResourceManager(), rts[i]);

    // need to unwrap here, as FromPortableHandle unwraps too.
    Unwrap(cmd)->OMSetRenderTargets((UINT)rts.size(), rtHandles, rtSingle ? TRUE : FALSE,
                                    dsv.heap != ResourceId() ? &dsvHandle : NULL);
  }

  if(graphics.rootsig != ResourceId())
  {
    cmd->SetGraphicsRootSignature(
        GetResourceManager()->GetCurrentAs<ID3D12RootSignature>(graphics.rootsig));

    for(size_t i = 0; i < graphics.sigelems.size(); i++)
    {
      // just don't set tables that aren't in the descriptor heaps, since it's invalid and can crash
      // and is probably just from stale bindings that aren't going to be used
      if(graphics.sigelems[i].type == eRootTable ||
         std::find(heaps.begin(), heaps.end(), graphics.sigelems[i].id) != heaps.end())
      {
        graphics.sigelems[i].SetToGraphics(GetResourceManager(), cmd, (UINT)i);
      }
      else
      {
        RDCDEBUG("Skipping setting possibly stale graphics root table referring to heap %llu",
                 graphics.sigelems[i].id);
      }
    }
  }

  if(compute.rootsig != ResourceId())
  {
    cmd->SetComputeRootSignature(
        GetResourceManager()->GetCurrentAs<ID3D12RootSignature>(compute.rootsig));

    for(size_t i = 0; i < compute.sigelems.size(); i++)
    {
      // just don't set tables that aren't in the descriptor heaps, since it's invalid and can crash
      // and is probably just from stale bindings that aren't going to be used
      if(compute.sigelems[i].type != eRootTable ||
         std::find(heaps.begin(), heaps.end(), compute.sigelems[i].id) != heaps.end())
      {
        compute.sigelems[i].SetToCompute(GetResourceManager(), cmd, (UINT)i);
      }
      else
      {
        RDCDEBUG("Skipping setting possibly stale compute root table referring to heap %llu",
                 compute.sigelems[i].id);
      }
    }
  }
}
Exemplo n.º 22
0
ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
{
  RDCDEBUG("Creating an OpenGL replay device");

  HMODULE lib = NULL;
  lib = LoadLibraryA("opengl32.dll");
  if(lib == NULL)
  {
    RDCERR("Failed to load opengl32.dll");
    return eReplayCreate_APIInitFailed;
  }

  GLInitParams initParams;
  RDCDriver driverType = RDC_OpenGL;
  string driverName = "OpenGL";
  uint64_t machineIdent = 0;
  if(logfile)
  {
    auto status = RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, machineIdent,
                                                   (RDCInitParams *)&initParams);
    if(status != eReplayCreate_Success)
      return status;
  }

  PIXELFORMATDESCRIPTOR pfd = {0};

  if(wglGetProc == NULL)
  {
    wglGetProc = (WGLGETPROCADDRESSPROC)GetProcAddress(lib, "wglGetProcAddress");
    wglCreateRC = (WGLCREATECONTEXTPROC)GetProcAddress(lib, "wglCreateContext");
    wglMakeCurrentProc = (WGLMAKECURRENTPROC)GetProcAddress(lib, "wglMakeCurrent");
    wglDeleteRC = (WGLDELETECONTEXTPROC)GetProcAddress(lib, "wglDeleteContext");

    if(wglGetProc == NULL || wglCreateRC == NULL || wglMakeCurrentProc == NULL || wglDeleteRC == NULL)
    {
      RDCERR("Couldn't get wgl function addresses");
      return eReplayCreate_APIInitFailed;
    }

    WNDCLASSEX wc;
    RDCEraseEl(wc);
    wc.style = CS_OWNDC;
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.lpfnWndProc = DefWindowProc;
    wc.hInstance = GetModuleHandle(NULL);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.lpszClassName = L"renderdocGLclass";

    if(!RegisterClassEx(&wc))
    {
      RDCERR("Couldn't register GL window class");
      return eReplayCreate_APIInitFailed;
    }

    RDCEraseEl(pfd);
    pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
    pfd.nVersion = 1;
    pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
    pfd.iLayerType = PFD_MAIN_PLANE;
    pfd.iPixelType = PFD_TYPE_RGBA;
    pfd.cColorBits = 32;
    pfd.cDepthBits = 24;
    pfd.cStencilBits = 0;
  }

  HWND w = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdocGLclass", L"", WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL,
                          GetModuleHandle(NULL), NULL);

  HDC dc = GetDC(w);

  int pf = ChoosePixelFormat(dc, &pfd);
  if(pf == 0)
  {
    RDCERR("Couldn't choose pixel format");
    return eReplayCreate_APIInitFailed;
  }

  BOOL res = SetPixelFormat(dc, pf, &pfd);
  if(res == FALSE)
  {
    RDCERR("Couldn't set pixel format");
    return eReplayCreate_APIInitFailed;
  }

  HGLRC rc = wglCreateRC(dc);
  if(rc == NULL)
  {
    RDCERR("Couldn't create simple RC");
    return eReplayCreate_APIInitFailed;
  }

  res = wglMakeCurrentProc(dc, rc);
  if(res == FALSE)
  {
    RDCERR("Couldn't make simple RC current");
    return eReplayCreate_APIInitFailed;
  }

  createContextAttribs =
      (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProc("wglCreateContextAttribsARB");
  getPixelFormatAttrib =
      (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProc("wglGetPixelFormatAttribivARB");

  if(createContextAttribs == NULL || getPixelFormatAttrib == NULL)
  {
    RDCERR("RenderDoc requires WGL_ARB_create_context and WGL_ARB_pixel_format");
    return eReplayCreate_APIHardwareUnsupported;
  }

  wglMakeCurrentProc(NULL, NULL);
  wglDeleteRC(rc);
  ReleaseDC(w, dc);
  DestroyWindow(w);

  GLReplay::PreContextInitCounters();

  // we don't use the default framebuffer (backbuffer) for anything, so we make it
  // tiny and with no depth/stencil bits
  pfd.iPixelType = PFD_TYPE_RGBA;
  pfd.cColorBits = 24;
  pfd.cDepthBits = 0;
  pfd.cStencilBits = 0;

  w = CreateWindowEx(WS_EX_CLIENTEDGE, L"renderdocGLclass", L"RenderDoc replay window",
                     WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 32, 32, NULL, NULL,
                     GetModuleHandle(NULL), NULL);

  dc = GetDC(w);

  pf = ChoosePixelFormat(dc, &pfd);
  if(pf == 0)
  {
    RDCERR("Couldn't choose pixel format");
    ReleaseDC(w, dc);
    GLReplay::PostContextShutdownCounters();
    return eReplayCreate_APIInitFailed;
  }

  res = SetPixelFormat(dc, pf, &pfd);
  if(res == FALSE)
  {
    RDCERR("Couldn't set pixel format");
    ReleaseDC(w, dc);
    GLReplay::PostContextShutdownCounters();
    return eReplayCreate_APIInitFailed;
  }

  int attribs[64] = {0};
  int i = 0;

  attribs[i++] = WGL_CONTEXT_MAJOR_VERSION_ARB;
  int &major = attribs[i];
  attribs[i++] = 0;
  attribs[i++] = WGL_CONTEXT_MINOR_VERSION_ARB;
  int &minor = attribs[i];
  attribs[i++] = 0;
  attribs[i++] = WGL_CONTEXT_FLAGS_ARB;
#if ENABLED(RDOC_DEVEL)
  attribs[i++] = WGL_CONTEXT_DEBUG_BIT_ARB;
#else
  attribs[i++] = 0;
#endif
  attribs[i++] = WGL_CONTEXT_PROFILE_MASK_ARB;
  attribs[i++] = WGL_CONTEXT_CORE_PROFILE_BIT_ARB;

  // try to create all versions from 4.5 down to 3.2 in order to get the
  // highest versioned context we can
  struct
  {
    int major;
    int minor;
  } versions[] = {
      {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, {3, 3}, {3, 2},
  };

  rc = NULL;

  for(size_t v = 0; v < ARRAY_COUNT(versions); v++)
  {
    major = versions[v].major;
    minor = versions[v].minor;
    rc = createContextAttribs(dc, NULL, attribs);

    if(rc)
      break;
  }
  if(rc == NULL)
  {
    RDCERR("Couldn't create 3.2 RC - RenderDoc requires OpenGL 3.2 availability");
    ReleaseDC(w, dc);
    GLReplay::PostContextShutdownCounters();
    return eReplayCreate_APIHardwareUnsupported;
  }

  GLCoreVersion = major * 10 + minor;

  res = wglMakeCurrentProc(dc, rc);
  if(res == FALSE)
  {
    RDCERR("Couldn't make 3.2 RC current");
    wglMakeCurrentProc(NULL, NULL);
    wglDeleteRC(rc);
    ReleaseDC(w, dc);
    GLReplay::PostContextShutdownCounters();
    return eReplayCreate_APIInitFailed;
  }

  PFNGLGETINTEGERVPROC getInt = (PFNGLGETINTEGERVPROC)GetProcAddress(lib, "glGetIntegerv");
  PFNGLGETSTRINGPROC getStr = (PFNGLGETSTRINGPROC)GetProcAddress(lib, "glGetString");
  PFNGLGETSTRINGIPROC getStri = (PFNGLGETSTRINGIPROC)wglGetProc("glGetStringi");

  if(getInt == NULL || getStr == NULL || getStri == NULL)
  {
    RDCERR("Couldn't get glGetIntegerv (%p), glGetString (%p) or glGetStringi (%p) entry points",
           getInt, getStr, getStri);
    wglMakeCurrentProc(NULL, NULL);
    wglDeleteRC(rc);
    ReleaseDC(w, dc);
    GLReplay::PostContextShutdownCounters();
    return eReplayCreate_APIInitFailed;
  }

  bool missingExt = CheckReplayContext(getStr, getInt, getStri);

  if(missingExt)
  {
    wglMakeCurrentProc(NULL, NULL);
    wglDeleteRC(rc);
    ReleaseDC(w, dc);
    GLReplay::PostContextShutdownCounters();
    return eReplayCreate_APIInitFailed;
  }

  const GLHookSet &real = GetRealGLFunctions();

  bool extensionsValidated = ValidateFunctionPointers(real);

  if(!extensionsValidated)
  {
    wglMakeCurrentProc(NULL, NULL);
    wglDeleteRC(rc);
    ReleaseDC(w, dc);
    GLReplay::PostContextShutdownCounters();
    return eReplayCreate_APIInitFailed;
  }

  WrappedOpenGL *gl = new WrappedOpenGL(logfile, real, GetGLPlatform());
  gl->Initialise(initParams);

  if(gl->GetSerialiser()->HasError())
  {
    delete gl;
    return eReplayCreate_FileIOFailed;
  }

  RDCLOG("Created device.");
  GLReplay *replay = gl->GetReplay();
  replay->SetProxy(logfile == NULL);
  GLWindowingData data;
  data.DC = dc;
  data.ctx = rc;
  data.wnd = w;
  replay->SetReplayData(data);

  *driver = (IReplayDriver *)replay;
  return eReplayCreate_Success;
}
Exemplo n.º 23
0
VkResult WrappedVulkan::vkQueueSubmit(VkQueue queue, uint32_t submitCount,
                                      const VkSubmitInfo *pSubmits, VkFence fence)
{
  SCOPED_DBG_SINK();

  size_t tempmemSize = sizeof(VkSubmitInfo) * submitCount;

  // need to count how many semaphore and command buffer arrays to allocate for
  for(uint32_t i = 0; i < submitCount; i++)
  {
    tempmemSize += pSubmits[i].commandBufferCount * sizeof(VkCommandBuffer);
    tempmemSize += pSubmits[i].signalSemaphoreCount * sizeof(VkSemaphore);
    tempmemSize += pSubmits[i].waitSemaphoreCount * sizeof(VkSemaphore);
  }

  byte *memory = GetTempMemory(tempmemSize);

  VkSubmitInfo *unwrappedSubmits = (VkSubmitInfo *)memory;
  VkSemaphore *unwrappedWaitSems = (VkSemaphore *)(unwrappedSubmits + submitCount);

  for(uint32_t i = 0; i < submitCount; i++)
  {
    RDCASSERT(pSubmits[i].sType == VK_STRUCTURE_TYPE_SUBMIT_INFO && pSubmits[i].pNext == NULL);
    unwrappedSubmits[i] = pSubmits[i];

    unwrappedSubmits[i].pWaitSemaphores =
        unwrappedSubmits[i].waitSemaphoreCount ? unwrappedWaitSems : NULL;
    for(uint32_t o = 0; o < unwrappedSubmits[i].waitSemaphoreCount; o++)
      unwrappedWaitSems[o] = Unwrap(pSubmits[i].pWaitSemaphores[o]);
    unwrappedWaitSems += unwrappedSubmits[i].waitSemaphoreCount;

    VkCommandBuffer *unwrappedCommandBuffers = (VkCommandBuffer *)unwrappedWaitSems;

    unwrappedSubmits[i].pCommandBuffers =
        unwrappedSubmits[i].commandBufferCount ? unwrappedCommandBuffers : NULL;
    for(uint32_t o = 0; o < unwrappedSubmits[i].commandBufferCount; o++)
      unwrappedCommandBuffers[o] = Unwrap(pSubmits[i].pCommandBuffers[o]);
    unwrappedCommandBuffers += unwrappedSubmits[i].commandBufferCount;

    VkSemaphore *unwrappedSignalSems = (VkSemaphore *)unwrappedCommandBuffers;

    unwrappedSubmits[i].pSignalSemaphores =
        unwrappedSubmits[i].signalSemaphoreCount ? unwrappedSignalSems : NULL;
    for(uint32_t o = 0; o < unwrappedSubmits[i].signalSemaphoreCount; o++)
      unwrappedSignalSems[o] = Unwrap(pSubmits[i].pSignalSemaphores[o]);
  }

  VkResult ret =
      ObjDisp(queue)->QueueSubmit(Unwrap(queue), submitCount, unwrappedSubmits, Unwrap(fence));

  bool capframe = false;
  set<ResourceId> refdIDs;

  for(uint32_t s = 0; s < submitCount; s++)
  {
    for(uint32_t i = 0; i < pSubmits[s].commandBufferCount; i++)
    {
      ResourceId cmd = GetResID(pSubmits[s].pCommandBuffers[i]);

      VkResourceRecord *record = GetRecord(pSubmits[s].pCommandBuffers[i]);

      {
        SCOPED_LOCK(m_ImageLayoutsLock);
        GetResourceManager()->ApplyBarriers(record->bakedCommands->cmdInfo->imgbarriers,
                                            m_ImageLayouts);
      }

      // need to lock the whole section of code, not just the check on
      // m_State, as we also need to make sure we don't check the state,
      // start marking dirty resources then while we're doing so the
      // state becomes capframe.
      // the next sections where we mark resources referenced and add
      // the submit chunk to the frame record don't have to be protected.
      // Only the decision of whether we're inframe or not, and marking
      // dirty.
      {
        SCOPED_LOCK(m_CapTransitionLock);
        if(m_State == WRITING_CAPFRAME)
        {
          for(auto it = record->bakedCommands->cmdInfo->dirtied.begin();
              it != record->bakedCommands->cmdInfo->dirtied.end(); ++it)
            GetResourceManager()->MarkPendingDirty(*it);

          capframe = true;
        }
        else
        {
          for(auto it = record->bakedCommands->cmdInfo->dirtied.begin();
              it != record->bakedCommands->cmdInfo->dirtied.end(); ++it)
            GetResourceManager()->MarkDirtyResource(*it);
        }
      }

      if(capframe)
      {
        // for each bound descriptor set, mark it referenced as well as all resources currently
        // bound to it
        for(auto it = record->bakedCommands->cmdInfo->boundDescSets.begin();
            it != record->bakedCommands->cmdInfo->boundDescSets.end(); ++it)
        {
          GetResourceManager()->MarkResourceFrameReferenced(GetResID(*it), eFrameRef_Read);

          VkResourceRecord *setrecord = GetRecord(*it);

          for(auto refit = setrecord->descInfo->bindFrameRefs.begin();
              refit != setrecord->descInfo->bindFrameRefs.end(); ++refit)
          {
            refdIDs.insert(refit->first);
            GetResourceManager()->MarkResourceFrameReferenced(refit->first, refit->second.second);

            if(refit->second.first & DescriptorSetData::SPARSE_REF_BIT)
            {
              VkResourceRecord *sparserecord = GetResourceManager()->GetResourceRecord(refit->first);

              GetResourceManager()->MarkSparseMapReferenced(sparserecord->sparseInfo);
            }
          }
        }

        for(auto it = record->bakedCommands->cmdInfo->sparse.begin();
            it != record->bakedCommands->cmdInfo->sparse.end(); ++it)
          GetResourceManager()->MarkSparseMapReferenced(*it);

        // pull in frame refs from this baked command buffer
        record->bakedCommands->AddResourceReferences(GetResourceManager());
        record->bakedCommands->AddReferencedIDs(refdIDs);

        // ref the parent command buffer by itself, this will pull in the cmd buffer pool
        GetResourceManager()->MarkResourceFrameReferenced(record->GetResourceID(), eFrameRef_Read);

        for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->subcmds.size(); sub++)
        {
          record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddResourceReferences(
              GetResourceManager());
          record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddReferencedIDs(refdIDs);
          GetResourceManager()->MarkResourceFrameReferenced(
              record->bakedCommands->cmdInfo->subcmds[sub]->GetResourceID(), eFrameRef_Read);

          record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands->AddRef();
        }

        GetResourceManager()->MarkResourceFrameReferenced(GetResID(queue), eFrameRef_Read);

        if(fence != VK_NULL_HANDLE)
          GetResourceManager()->MarkResourceFrameReferenced(GetResID(fence), eFrameRef_Read);

        {
          SCOPED_LOCK(m_CmdBufferRecordsLock);
          m_CmdBufferRecords.push_back(record->bakedCommands);
          for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->subcmds.size(); sub++)
            m_CmdBufferRecords.push_back(record->bakedCommands->cmdInfo->subcmds[sub]->bakedCommands);
        }

        record->bakedCommands->AddRef();
      }

      record->cmdInfo->dirtied.clear();
    }
  }

  if(capframe)
  {
    vector<VkResourceRecord *> maps;
    {
      SCOPED_LOCK(m_CoherentMapsLock);
      maps = m_CoherentMaps;
    }

    for(auto it = maps.begin(); it != maps.end(); ++it)
    {
      VkResourceRecord *record = *it;
      MemMapState &state = *record->memMapState;

      // potential persistent map
      if(state.mapCoherent && state.mappedPtr && !state.mapFlushed)
      {
        // only need to flush memory that could affect this submitted batch of work
        if(refdIDs.find(record->GetResourceID()) == refdIDs.end())
        {
          RDCDEBUG("Map of memory %llu not referenced in this queue - not flushing",
                   record->GetResourceID());
          continue;
        }

        size_t diffStart = 0, diffEnd = 0;
        bool found = true;

// enabled as this is necessary for programs with very large coherent mappings
// (> 1GB) as otherwise more than a couple of vkQueueSubmit calls leads to vast
// memory allocation. There might still be bugs lurking in here though
#if 1
        // this causes vkFlushMappedMemoryRanges call to allocate and copy to refData
        // from serialised buffer. We want to copy *precisely* the serialised data,
        // otherwise there is a gap in time between serialising out a snapshot of
        // the buffer and whenever we then copy into the ref data, e.g. below.
        // during this time, data could be written to the buffer and it won't have
        // been caught in the serialised snapshot, and if it doesn't change then
        // it *also* won't be caught in any future FindDiffRange() calls.
        //
        // Likewise once refData is allocated, the call below will also update it
        // with the data serialised out for the same reason.
        //
        // Note: it's still possible that data is being written to by the
        // application while it's being serialised out in the snapshot below. That
        // is OK, since the application is responsible for ensuring it's not writing
        // data that would be needed by the GPU in this submit. As long as the
        // refdata we use for future use is identical to what was serialised, we
        // shouldn't miss anything
        state.needRefData = true;

        // if we have a previous set of data, compare.
        // otherwise just serialise it all
        if(state.refData)
          found = FindDiffRange((byte *)state.mappedPtr, state.refData, (size_t)state.mapSize,
                                diffStart, diffEnd);
        else
#endif
          diffEnd = (size_t)state.mapSize;

        if(found)
        {
          // MULTIDEVICE should find the device for this queue.
          // MULTIDEVICE only want to flush maps associated with this queue
          VkDevice dev = GetDev();

          {
            RDCLOG("Persistent map flush forced for %llu (%llu -> %llu)", record->GetResourceID(),
                   (uint64_t)diffStart, (uint64_t)diffEnd);
            VkMappedMemoryRange range = {VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, NULL,
                                         (VkDeviceMemory)(uint64_t)record->Resource,
                                         state.mapOffset + diffStart, diffEnd - diffStart};
            vkFlushMappedMemoryRanges(dev, 1, &range);
            state.mapFlushed = false;
          }

          GetResourceManager()->MarkPendingDirty(record->GetResourceID());
        }
        else
        {
          RDCDEBUG("Persistent map flush not needed for %llu", record->GetResourceID());
        }
      }
    }

    {
      CACHE_THREAD_SERIALISER();

      for(uint32_t s = 0; s < submitCount; s++)
      {
        SCOPED_SERIALISE_CONTEXT(QUEUE_SUBMIT);
        Serialise_vkQueueSubmit(localSerialiser, queue, 1, &pSubmits[s], fence);

        m_FrameCaptureRecord->AddChunk(scope.Get());

        for(uint32_t sem = 0; sem < pSubmits[s].waitSemaphoreCount; sem++)
          GetResourceManager()->MarkResourceFrameReferenced(
              GetResID(pSubmits[s].pWaitSemaphores[sem]), eFrameRef_Read);

        for(uint32_t sem = 0; sem < pSubmits[s].signalSemaphoreCount; sem++)
          GetResourceManager()->MarkResourceFrameReferenced(
              GetResID(pSubmits[s].pSignalSemaphores[sem]), eFrameRef_Read);
      }
    }
  }

  return ret;
}
Exemplo n.º 24
0
Socket *CreateClientSocket(const char *host, uint16_t port, int timeoutMS)
{
	wchar_t portwstr[7] = {0};

	{
		char buf[7] = {0};
		int n = StringFormat::snprintf(buf, 6, "%d", port);
		for(int i=0; i < n && i < 6; i++) portwstr[i] = (wchar_t)buf[i];
	}

	addrinfoW hints;
	RDCEraseEl(hints);
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = IPPROTO_TCP;

	std::wstring whost = StringFormat::UTF82Wide(string(host));

	addrinfoW *addrResult = NULL;
	GetAddrInfoW(whost.c_str(), portwstr, &hints, &addrResult);

	for(addrinfoW *ptr = addrResult; ptr != NULL; ptr = ptr->ai_next)
	{
		SOCKET s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT);

		if(s == INVALID_SOCKET)
			return NULL;

		u_long enable = 1;
		ioctlsocket(s, FIONBIO, &enable);

		int result = connect(s, ptr->ai_addr, (int)ptr->ai_addrlen);
		if(result == SOCKET_ERROR)
		{
			fd_set set;
			FD_ZERO(&set);

			// macro FD_SET contains the do { } while(0) idiom, which warns
#pragma warning(push)
#pragma warning(disable : 4127) // conditional expression is constant
			FD_SET(s, &set);
#pragma warning(pop)

			int err = WSAGetLastError();

			if(err == WSAEWOULDBLOCK)
			{
				timeval timeout;
				timeout.tv_sec = (timeoutMS/1000);
				timeout.tv_usec = (timeoutMS%1000)*1000;
				result = select(0, NULL, &set, NULL, &timeout);

				if(result <= 0)
				{
					RDCDEBUG("connect timed out");
					closesocket(s);
					continue;
				}
				else
				{
					RDCDEBUG("connect before timeout");
				}
			}
			else
			{
				RDCDEBUG("problem other than blocking");
				closesocket(s);
				continue;
			}
		}
		else
		{
			RDCDEBUG("connected immediately");
		}

		BOOL nodelay = TRUE;
		setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (const char *)&nodelay, sizeof(nodelay));

		return new Socket((ptrdiff_t)s);
	}

	RDCWARN("Failed to connect to %s:%d", host, port);
	return NULL;
}
Exemplo n.º 25
0
VkResult WrappedVulkan::vkCreateDevice(
		VkPhysicalDevice                            physicalDevice,
		const VkDeviceCreateInfo*                   pCreateInfo,
		const VkAllocationCallbacks*                pAllocator,
		VkDevice*                                   pDevice)
{
	VkDeviceCreateInfo createInfo = *pCreateInfo;

	uint32_t qCount = 0;
	VkResult vkr = VK_SUCCESS;
	
	ObjDisp(physicalDevice)->GetPhysicalDeviceQueueFamilyProperties(Unwrap(physicalDevice), &qCount, NULL);

	VkQueueFamilyProperties *props = new VkQueueFamilyProperties[qCount];
	ObjDisp(physicalDevice)->GetPhysicalDeviceQueueFamilyProperties(Unwrap(physicalDevice), &qCount, props);

	// find a queue that supports all capabilities, and if one doesn't exist, add it.
	bool found = false;
	uint32_t qFamilyIdx = 0;
	VkQueueFlags search = (VK_QUEUE_GRAPHICS_BIT);

	// for queue priorities, if we need it
	float one = 1.0f;

	// if we need to change the requested queues, it will point to this
	VkDeviceQueueCreateInfo *modQueues = NULL;

	for(uint32_t i=0; i < createInfo.queueCreateInfoCount; i++)
	{
		uint32_t idx = createInfo.pQueueCreateInfos[i].queueFamilyIndex;
		RDCASSERT(idx < qCount);

		// this requested queue is one we can use too
		if((props[idx].queueFlags & search) == search && createInfo.pQueueCreateInfos[i].queueCount > 0)
		{
			qFamilyIdx = idx;
			found = true;
			break;
		}
	}

	// if we didn't find it, search for which queue family we should add a request for
	if(!found)
	{
		RDCDEBUG("App didn't request a queue family we can use - adding our own");

		for(uint32_t i=0; i < qCount; i++)
		{
			if((props[i].queueFlags & search) == search)
			{
				qFamilyIdx = i;
				found = true;
				break;
			}
		}

		if(!found)
		{
			SAFE_DELETE_ARRAY(props);
			RDCERR("Can't add a queue with required properties for RenderDoc! Unsupported configuration");
			return VK_ERROR_INITIALIZATION_FAILED;
		}

		// we found the queue family, add it
		modQueues = new VkDeviceQueueCreateInfo[createInfo.queueCreateInfoCount + 1];
		for(uint32_t i=0; i < createInfo.queueCreateInfoCount; i++)
			modQueues[i] = createInfo.pQueueCreateInfos[i];

		modQueues[createInfo.queueCreateInfoCount].queueFamilyIndex = qFamilyIdx;
		modQueues[createInfo.queueCreateInfoCount].queueCount = 1;
		modQueues[createInfo.queueCreateInfoCount].pQueuePriorities = &one;

		createInfo.pQueueCreateInfos = modQueues;
		createInfo.queueCreateInfoCount++;
	}

	SAFE_DELETE_ARRAY(props);

	m_QueueFamilies.resize(createInfo.queueCreateInfoCount);
	for(size_t i=0; i < createInfo.queueCreateInfoCount; i++)
	{
		uint32_t family = createInfo.pQueueCreateInfos[i].queueFamilyIndex;
		uint32_t count = createInfo.pQueueCreateInfos[i].queueCount;
		m_QueueFamilies.resize(RDCMAX(m_QueueFamilies.size(), size_t(family+1)));

		m_QueueFamilies[family] = new VkQueue[count];
		for(uint32_t q=0; q < count; q++)
			m_QueueFamilies[family][q] = VK_NULL_HANDLE;
	}

	VkLayerDeviceCreateInfo *layerCreateInfo = (VkLayerDeviceCreateInfo *)pCreateInfo->pNext;

	// step through the chain of pNext until we get to the link info
	while(layerCreateInfo &&
				(layerCreateInfo->sType != VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO || 
				 layerCreateInfo->function != VK_LAYER_LINK_INFO)
			)
	{
		layerCreateInfo = (VkLayerDeviceCreateInfo *)layerCreateInfo->pNext;
	}
	RDCASSERT(layerCreateInfo);

	PFN_vkGetDeviceProcAddr gdpa = layerCreateInfo->u.pLayerInfo->pfnNextGetDeviceProcAddr;
	PFN_vkGetInstanceProcAddr gipa = layerCreateInfo->u.pLayerInfo->pfnNextGetInstanceProcAddr;
	// move chain on for next layer
	layerCreateInfo->u.pLayerInfo = layerCreateInfo->u.pLayerInfo->pNext;

	PFN_vkCreateDevice createFunc = (PFN_vkCreateDevice)gipa(VK_NULL_HANDLE, "vkCreateDevice");

	// now search again through for the loader data callback (if it exists)
	layerCreateInfo = (VkLayerDeviceCreateInfo *)pCreateInfo->pNext;

	// step through the chain of pNext
	while(layerCreateInfo &&
				(layerCreateInfo->sType != VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO || 
				 layerCreateInfo->function != VK_LOADER_DATA_CALLBACK)
			)
	{
		layerCreateInfo = (VkLayerDeviceCreateInfo *)layerCreateInfo->pNext;
	}

	// if we found one (we might not - on old loaders), then store the func ptr for
	// use instead of SetDispatchTableOverMagicNumber
	if(layerCreateInfo)
	{
		RDCASSERT(m_SetDeviceLoaderData == layerCreateInfo->u.pfnSetDeviceLoaderData || m_SetDeviceLoaderData == NULL,
		          m_SetDeviceLoaderData, layerCreateInfo->u.pfnSetDeviceLoaderData);
		m_SetDeviceLoaderData = layerCreateInfo->u.pfnSetDeviceLoaderData;
	}

	VkResult ret = createFunc(Unwrap(physicalDevice), &createInfo, pAllocator, pDevice);
	
	// don't serialise out any of the pNext stuff for layer initialisation
	// (note that we asserted above that there was nothing else in the chain)
	createInfo.pNext = NULL;

	if(ret == VK_SUCCESS)
	{
		InitDeviceTable(*pDevice, gdpa);

		ResourceId id = GetResourceManager()->WrapResource(*pDevice, *pDevice);
		
		if(m_State >= WRITING)
		{
			Chunk *chunk = NULL;

			{
				CACHE_THREAD_SERIALISER();

				SCOPED_SERIALISE_CONTEXT(CREATE_DEVICE);
				Serialise_vkCreateDevice(localSerialiser, physicalDevice, &createInfo, NULL, pDevice);

				chunk = scope.Get();
			}

			VkResourceRecord *record = GetResourceManager()->AddResourceRecord(*pDevice);
			RDCASSERT(record);

			record->AddChunk(chunk);

			record->memIdxMap = GetRecord(physicalDevice)->memIdxMap;

			record->instDevInfo = new InstanceDeviceInfo();
		
#undef CheckExt
#define CheckExt(name) record->instDevInfo->name = GetRecord(m_Instance)->instDevInfo->name;

			// inherit extension enablement from instance, that way GetDeviceProcAddress can check
			// for enabled extensions for instance functions
			CheckInstanceExts();

#undef CheckExt
#define CheckExt(name) if(!strcmp(createInfo.ppEnabledExtensionNames[i], STRINGIZE(name))) { record->instDevInfo->name = true; }

			for(uint32_t i=0; i < createInfo.enabledExtensionCount; i++)
			{
				CheckDeviceExts();
			}
		
			InitDeviceExtensionTables(*pDevice);

			GetRecord(m_Instance)->AddParent(record);
		}
		else
		{
			GetResourceManager()->AddLiveResource(id, *pDevice);
		}

		VkDevice device = *pDevice;

		RDCASSERT(m_Device == VK_NULL_HANDLE); // MULTIDEVICE

		m_PhysicalDevice = physicalDevice;
		m_Device = device;

		m_QueueFamilyIdx = qFamilyIdx;

		if(m_InternalCmds.cmdpool == VK_NULL_HANDLE)
		{
			VkCommandPoolCreateInfo poolInfo = { VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, NULL, VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, qFamilyIdx };
			vkr = ObjDisp(device)->CreateCommandPool(Unwrap(device), &poolInfo, NULL, &m_InternalCmds.cmdpool);
			RDCASSERTEQUAL(vkr, VK_SUCCESS);

			GetResourceManager()->WrapResource(Unwrap(device), m_InternalCmds.cmdpool);
		}
		
		ObjDisp(physicalDevice)->GetPhysicalDeviceProperties(Unwrap(physicalDevice), &m_PhysicalDeviceData.props);
		
		ObjDisp(physicalDevice)->GetPhysicalDeviceMemoryProperties(Unwrap(physicalDevice), &m_PhysicalDeviceData.memProps);

		ObjDisp(physicalDevice)->GetPhysicalDeviceFeatures(Unwrap(physicalDevice), &m_PhysicalDeviceData.features);

		m_PhysicalDeviceData.readbackMemIndex = m_PhysicalDeviceData.GetMemoryIndex(~0U, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 0);
		m_PhysicalDeviceData.uploadMemIndex = m_PhysicalDeviceData.GetMemoryIndex(~0U, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, 0);
		m_PhysicalDeviceData.GPULocalMemIndex = m_PhysicalDeviceData.GetMemoryIndex(~0U, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);

		m_PhysicalDeviceData.fakeMemProps = GetRecord(physicalDevice)->memProps;

		m_DebugManager = new VulkanDebugManager(this, device);
	}

	SAFE_DELETE_ARRAY(modQueues);

	return ret;
}
Exemplo n.º 26
0
void STDMETHODCALLTYPE WrappedID3D12CommandQueue::ExecuteCommandLists(
    UINT NumCommandLists, ID3D12CommandList *const *ppCommandLists)
{
  ID3D12CommandList **unwrapped = m_pDevice->GetTempArray<ID3D12CommandList *>(NumCommandLists);
  for(UINT i = 0; i < NumCommandLists; i++)
    unwrapped[i] = Unwrap(ppCommandLists[i]);

  m_pReal->ExecuteCommandLists(NumCommandLists, unwrapped);

  if(m_State >= WRITING)
  {
    SCOPED_LOCK(m_Lock);
    SCOPED_LOCK(m_pDevice->GetCapTransitionLock());

    bool capframe = (m_State == WRITING_CAPFRAME);
    set<ResourceId> refdIDs;

    for(UINT i = 0; i < NumCommandLists; i++)
    {
      D3D12ResourceRecord *record = GetRecord(ppCommandLists[i]);

      if(record->ContainsExecuteIndirect)
        m_QueueRecord->ContainsExecuteIndirect = true;

      m_pDevice->ApplyBarriers(record->bakedCommands->cmdInfo->barriers);

      // need to lock the whole section of code, not just the check on
      // m_State, as we also need to make sure we don't check the state,
      // start marking dirty resources then while we're doing so the
      // state becomes capframe.
      // the next sections where we mark resources referenced and add
      // the submit chunk to the frame record don't have to be protected.
      // Only the decision of whether we're inframe or not, and marking
      // dirty.
      if(capframe)
      {
        for(auto it = record->bakedCommands->cmdInfo->dirtied.begin();
            it != record->bakedCommands->cmdInfo->dirtied.end(); ++it)
          GetResourceManager()->MarkPendingDirty(*it);
      }
      else
      {
        for(auto it = record->bakedCommands->cmdInfo->dirtied.begin();
            it != record->bakedCommands->cmdInfo->dirtied.end(); ++it)
          GetResourceManager()->MarkDirtyResource(*it);
      }

      if(capframe)
      {
        // any descriptor copies or writes could reference new resources not in the
        // bound descs list yet. So we take all of those referenced descriptors and
        // include them to see if we need to flush
        std::vector<D3D12Descriptor> dynDescRefs;
        m_pDevice->GetDynamicDescriptorReferences(dynDescRefs);

        for(size_t d = 0; d < dynDescRefs.size(); d++)
        {
          ResourceId id, id2;
          FrameRefType ref = eFrameRef_Read;

          dynDescRefs[d].GetRefIDs(id, id2, ref);

          if(id != ResourceId())
          {
            refdIDs.insert(id);
            GetResourceManager()->MarkResourceFrameReferenced(id, ref);
          }

          if(id2 != ResourceId())
          {
            refdIDs.insert(id2);
            GetResourceManager()->MarkResourceFrameReferenced(id2, ref);
          }
        }

        // for each bound descriptor table, mark it referenced as well as all resources currently
        // bound to it
        for(auto it = record->bakedCommands->cmdInfo->boundDescs.begin();
            it != record->bakedCommands->cmdInfo->boundDescs.end(); ++it)
        {
          D3D12Descriptor *desc = *it;

          ResourceId id, id2;
          FrameRefType ref = eFrameRef_Read;

          desc->GetRefIDs(id, id2, ref);

          if(id != ResourceId())
          {
            refdIDs.insert(id);
            GetResourceManager()->MarkResourceFrameReferenced(id, ref);
          }

          if(id2 != ResourceId())
          {
            refdIDs.insert(id2);
            GetResourceManager()->MarkResourceFrameReferenced(id2, ref);
          }
        }

        // pull in frame refs from this baked command list
        record->bakedCommands->AddResourceReferences(GetResourceManager());
        record->bakedCommands->AddReferencedIDs(refdIDs);

        // reference all executed bundles as well
        for(size_t b = 0; b < record->bakedCommands->cmdInfo->bundles.size(); b++)
        {
          record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddResourceReferences(
              GetResourceManager());
          record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddReferencedIDs(refdIDs);
          GetResourceManager()->MarkResourceFrameReferenced(
              record->bakedCommands->cmdInfo->bundles[b]->GetResourceID(), eFrameRef_Read);

          record->bakedCommands->cmdInfo->bundles[b]->bakedCommands->AddRef();
        }

        {
          m_CmdListRecords.push_back(record->bakedCommands);
          for(size_t sub = 0; sub < record->bakedCommands->cmdInfo->bundles.size(); sub++)
            m_CmdListRecords.push_back(record->bakedCommands->cmdInfo->bundles[sub]->bakedCommands);
        }

        record->bakedCommands->AddRef();
      }

      record->cmdInfo->dirtied.clear();
    }

    if(capframe)
    {
      vector<MapState> maps = m_pDevice->GetMaps();

      for(auto it = maps.begin(); it != maps.end(); ++it)
      {
        WrappedID3D12Resource *res = it->res;
        UINT subres = it->subres;
        size_t size = (size_t)it->totalSize;

        // only need to flush memory that could affect this submitted batch of work
        if(refdIDs.find(res->GetResourceID()) == refdIDs.end())
        {
          RDCDEBUG("Map of memory %llu not referenced in this queue - not flushing",
                   res->GetResourceID());
          continue;
        }

        size_t diffStart = 0, diffEnd = 0;
        bool found = true;

        byte *ref = res->GetShadow(subres);
        byte *data = res->GetMap(subres);

        if(ref)
          found = FindDiffRange(data, ref, size, diffStart, diffEnd);
        else
          diffEnd = size;

        if(found)
        {
          RDCLOG("Persistent map flush forced for %llu (%llu -> %llu)", res->GetResourceID(),
                 (uint64_t)diffStart, (uint64_t)diffEnd);

          D3D12_RANGE range = {diffStart, diffEnd};

          m_pDevice->MapDataWrite(res, subres, data, range);

          if(ref == NULL)
          {
            res->AllocShadow(subres, size);

            ref = res->GetShadow(subres);
          }

          // update comparison shadow for next time
          memcpy(ref, res->GetMap(subres), size);

          GetResourceManager()->MarkPendingDirty(res->GetResourceID());
        }
        else
        {
          RDCDEBUG("Persistent map flush not needed for %llu", res->GetResourceID());
        }
      }

      for(UINT i = 0; i < NumCommandLists; i++)
      {
        SCOPED_SERIALISE_CONTEXT(EXECUTE_CMD_LISTS);
        Serialise_ExecuteCommandLists(1, ppCommandLists + i);

        m_QueueRecord->AddChunk(scope.Get());
      }
    }
  }
}
Exemplo n.º 27
0
    static BOOL WINAPI Hook_CreateProcessW(
        PFN_CREATE_PROCESS_W realFunc, __in_opt LPCWSTR lpApplicationName,
        __inout_opt LPWSTR lpCommandLine, __in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
        __in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes, __in BOOL bInheritHandles,
        __in DWORD dwCreationFlags, __in_opt LPVOID lpEnvironment, __in_opt LPCWSTR lpCurrentDirectory,
        __in LPSTARTUPINFOW lpStartupInfo, __out LPPROCESS_INFORMATION lpProcessInformation)
    {
        PROCESS_INFORMATION dummy;
        RDCEraseEl(dummy);

        // not sure if this is valid, but I need the PID so I'll fill in my own struct to ensure that.
        if(lpProcessInformation == NULL)
        {
            lpProcessInformation = &dummy;
        }
        else
        {
            *lpProcessInformation = dummy;
        }

        dwCreationFlags |= CREATE_SUSPENDED;

        BOOL ret = realFunc(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes,
                            bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory,
                            lpStartupInfo, lpProcessInformation);

        if(ret && RenderDoc::Inst().GetCaptureOptions().HookIntoChildren)
        {
            RDCDEBUG("Intercepting CreateProcessW");

            bool inject = true;

            // sanity check to make sure we're not going to go into an infinity loop injecting into
            // ourselves.
            if(lpApplicationName)
            {
                wstring app = lpApplicationName;
                app = strlower(app);

                if(app.find(L"renderdoccmd.exe") != wstring::npos ||
                        app.find(L"renderdocui.vshost.exe") != wstring::npos ||
                        app.find(L"qrenderdoc.exe") != string::npos ||
                        app.find(L"renderdocui.exe") != wstring::npos)
                {
                    inject = false;
                }
            }
            if(lpCommandLine)
            {
                wstring cmd = lpCommandLine;
                cmd = strlower(cmd);

                if(cmd.find(L"renderdoccmd.exe") != wstring::npos ||
                        cmd.find(L"renderdocui.vshost.exe") != wstring::npos ||
                        cmd.find(L"qrenderdoc.exe") != wstring::npos ||
                        cmd.find(L"renderdocui.exe") != wstring::npos)
                {
                    inject = false;
                }
            }

            if(inject)
            {
                // inherit logfile and capture options
                uint32_t ident = RENDERDOC_InjectIntoProcess(lpProcessInformation->dwProcessId, NULL,
                                 RenderDoc::Inst().GetLogFile(),
                                 &RenderDoc::Inst().GetCaptureOptions(), false);

                RenderDoc::Inst().AddChildProcess((uint32_t)lpProcessInformation->dwProcessId, ident);
            }
        }

        ResumeThread(lpProcessInformation->hThread);

        // ensure we clean up after ourselves
        if(dummy.dwProcessId != 0)
        {
            CloseHandle(dummy.hProcess);
            CloseHandle(dummy.hThread);
        }

        return ret;
    }
Exemplo n.º 28
0
bool WrappedID3D12CommandQueue::Serialise_ExecuteCommandLists(UINT NumCommandLists,
                                                              ID3D12CommandList *const *ppCommandLists)
{
  SERIALISE_ELEMENT(ResourceId, queueId, GetResourceID());
  SERIALISE_ELEMENT(UINT, numCmds, NumCommandLists);

  vector<ResourceId> cmdIds;
  ID3D12GraphicsCommandList **cmds =
      m_State >= WRITING ? NULL : new ID3D12GraphicsCommandList *[numCmds];

  if(m_State >= WRITING)
  {
    for(UINT i = 0; i < numCmds; i++)
    {
      D3D12ResourceRecord *record = GetRecord(ppCommandLists[i]);
      RDCASSERT(record->bakedCommands);
      if(record->bakedCommands)
        cmdIds.push_back(record->bakedCommands->GetResourceID());
    }
  }

  m_pSerialiser->Serialise("ppCommandLists", cmdIds);

  if(m_State < WRITING)
  {
    for(UINT i = 0; i < numCmds; i++)
    {
      cmds[i] = cmdIds[i] != ResourceId()
                    ? GetResourceManager()->GetLiveAs<ID3D12GraphicsCommandList>(cmdIds[i])
                    : NULL;
    }
  }

  const string desc = m_pSerialiser->GetDebugStr();

  // debug messages
  {
    vector<DebugMessage> debugMessages;

    if(m_State == WRITING_CAPFRAME)
      debugMessages = m_pDevice->GetDebugMessages();

    SERIALISE_ELEMENT(uint32_t, NumMessages, (uint32_t)debugMessages.size());

    for(uint32_t i = 0; i < NumMessages; i++)
    {
      ScopedContext msgscope(m_pSerialiser, "DebugMessage", "DebugMessage", 0, false);

      string msgDesc;
      if(m_State >= WRITING)
        msgDesc = debugMessages[i].description.elems;

      SERIALISE_ELEMENT(uint32_t, Category, debugMessages[i].category);
      SERIALISE_ELEMENT(uint32_t, Severity, debugMessages[i].severity);
      SERIALISE_ELEMENT(uint32_t, ID, debugMessages[i].messageID);
      SERIALISE_ELEMENT(string, Description, msgDesc);

      if(m_State == READING)
      {
        DebugMessage msg;
        msg.source = eDbgSource_API;
        msg.category = (DebugMessageCategory)Category;
        msg.severity = (DebugMessageSeverity)Severity;
        msg.messageID = ID;
        msg.description = Description;

        m_Cmd.m_EventMessages.push_back(msg);
      }
    }
  }

  ID3D12CommandQueue *real = NULL;

  if(m_State <= EXECUTING)
    real = Unwrap(GetResourceManager()->GetLiveAs<ID3D12CommandQueue>(queueId));

  if(m_State == READING)
  {
    for(uint32_t i = 0; i < numCmds; i++)
    {
      if(m_Cmd.m_BakedCmdListInfo[cmdIds[i]].executeEvents.empty() ||
         m_Cmd.m_BakedCmdListInfo[cmdIds[i]].executeEvents[0].patched)
      {
        ID3D12CommandList *list = Unwrap(cmds[i]);
        real->ExecuteCommandLists(1, &list);
#if ENABLED(SINGLE_FLUSH_VALIDATE)
        m_pDevice->GPUSync();
#endif
      }
      else
      {
        BakedCmdListInfo &info = m_Cmd.m_BakedCmdListInfo[cmdIds[i]];

        // execute the first half of the cracked list
        ID3D12CommandList *list = Unwrap(info.crackedLists[0]);
        real->ExecuteCommandLists(1, &list);

        for(size_t c = 1; c < info.crackedLists.size(); c++)
        {
          m_pDevice->GPUSync();

          // readback the patch buffer and perform patching
          m_ReplayList->PatchExecuteIndirect(info, uint32_t(c - 1));

          // execute next list with this indirect.
          list = Unwrap(info.crackedLists[c]);
          real->ExecuteCommandLists(1, &list);
        }

#if ENABLED(SINGLE_FLUSH_VALIDATE)
        m_pDevice->GPUSync();
#endif
      }
    }

    for(uint32_t i = 0; i < numCmds; i++)
    {
      ResourceId cmd = GetResourceManager()->GetLiveID(cmdIds[i]);
      m_pDevice->ApplyBarriers(m_Cmd.m_BakedCmdListInfo[cmd].barriers);
    }

    m_Cmd.AddEvent(desc);

    // we're adding multiple events, need to increment ourselves
    m_Cmd.m_RootEventID++;

    string basename = "ExecuteCommandLists(" + ToStr::Get(numCmds) + ")";

    for(uint32_t c = 0; c < numCmds; c++)
    {
      string name = StringFormat::Fmt("=> %s[%u]: ID3D12CommandList(%s)", basename.c_str(), c,
                                      ToStr::Get(cmdIds[c]).c_str());

      // add a fake marker
      FetchDrawcall draw;
      draw.name = name;
      draw.flags |= eDraw_SetMarker;
      m_Cmd.AddEvent(name);
      m_Cmd.AddDrawcall(draw, true);
      m_Cmd.m_RootEventID++;

      BakedCmdListInfo &cmdBufInfo = m_Cmd.m_BakedCmdListInfo[cmdIds[c]];

      // insert the baked command list in-line into this list of notes, assigning new event and
      // drawIDs
      m_Cmd.InsertDrawsAndRefreshIDs(cmdIds[c], cmdBufInfo.draw->children);

      for(size_t e = 0; e < cmdBufInfo.draw->executedCmds.size(); e++)
      {
        vector<uint32_t> &submits =
            m_Cmd.m_Partial[D3D12CommandData::Secondary].cmdListExecs[cmdBufInfo.draw->executedCmds[e]];

        for(size_t s = 0; s < submits.size(); s++)
          submits[s] += m_Cmd.m_RootEventID;
      }

      for(size_t i = 0; i < cmdBufInfo.debugMessages.size(); i++)
      {
        DebugMessage msg = cmdBufInfo.debugMessages[i];
        msg.eventID += m_Cmd.m_RootEventID;
        m_pDevice->AddDebugMessage(msg);
      }

      // only primary command lists can be submitted
      m_Cmd.m_Partial[D3D12CommandData::Primary].cmdListExecs[cmdIds[c]].push_back(
          m_Cmd.m_RootEventID);

      m_Cmd.m_RootEventID += cmdBufInfo.eventCount;
      m_Cmd.m_RootDrawcallID += cmdBufInfo.drawCount;

      name = StringFormat::Fmt("=> %s[%u]: Close(%s)", basename.c_str(), c,
                               ToStr::Get(cmdIds[c]).c_str());
      draw.name = name;
      m_Cmd.AddEvent(name);
      m_Cmd.AddDrawcall(draw, true);
      m_Cmd.m_RootEventID++;
    }

    // account for the outer loop thinking we've added one event and incrementing,
    // since we've done all the handling ourselves this will be off by one.
    m_Cmd.m_RootEventID--;
  }
  else if(m_State == EXECUTING)
  {
    // account for the queue submit event
    m_Cmd.m_RootEventID++;

    uint32_t startEID = m_Cmd.m_RootEventID;

    // advance m_CurEventID to match the events added when reading
    for(uint32_t c = 0; c < numCmds; c++)
    {
      // 2 extra for the virtual labels around the command list
      m_Cmd.m_RootEventID += 2 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].eventCount;
      m_Cmd.m_RootDrawcallID += 2 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].drawCount;
    }

    // same accounting for the outer loop as above
    m_Cmd.m_RootEventID--;

    if(numCmds == 0)
    {
      // do nothing, don't bother with the logic below
    }
    else if(m_Cmd.m_LastEventID <= startEID)
    {
#if ENABLED(VERBOSE_PARTIAL_REPLAY)
      RDCDEBUG("Queue Submit no replay %u == %u", m_Cmd.m_LastEventID, startEID);
#endif
    }
    else if(m_Cmd.m_DrawcallCallback && m_Cmd.m_DrawcallCallback->RecordAllCmds())
    {
#if ENABLED(VERBOSE_PARTIAL_REPLAY)
      RDCDEBUG("Queue Submit re-recording from %u", m_Cmd.m_RootEventID);
#endif

      vector<ID3D12CommandList *> rerecordedCmds;

      for(uint32_t c = 0; c < numCmds; c++)
      {
        ID3D12CommandList *cmd = m_Cmd.RerecordCmdList(cmdIds[c]);
        ResourceId rerecord = GetResID(cmd);
#if ENABLED(VERBOSE_PARTIAL_REPLAY)
        RDCDEBUG("Queue Submit fully re-recorded replay of %llu, using %llu", cmdIds[c], rerecord);
#endif
        rerecordedCmds.push_back(Unwrap(cmd));

        m_pDevice->ApplyBarriers(m_Cmd.m_BakedCmdListInfo[rerecord].barriers);
      }

#if ENABLED(SINGLE_FLUSH_VALIDATE)
      for(size_t i = 0; i < rerecordedCmds.size(); i++)
      {
        real->ExecuteCommandLists(1, &rerecordedCmds[i]);
        m_pDevice->GPUSync();
      }
#else
      real->ExecuteCommandLists((UINT)rerecordedCmds.size(), &rerecordedCmds[0]);
#endif
    }
    else if(m_Cmd.m_LastEventID > startEID && m_Cmd.m_LastEventID < m_Cmd.m_RootEventID)
    {
#if ENABLED(VERBOSE_PARTIAL_REPLAY)
      RDCDEBUG("Queue Submit partial replay %u < %u", m_Cmd.m_LastEventID, m_Cmd.m_RootEventID);
#endif

      uint32_t eid = startEID;

      vector<ResourceId> trimmedCmdIds;
      vector<ID3D12CommandList *> trimmedCmds;

      for(uint32_t c = 0; c < numCmds; c++)
      {
        // account for the virtual label at the start of the events here
        // so it matches up to baseEvent
        eid++;

        uint32_t end = eid + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].eventCount;

        if(eid == m_Cmd.m_Partial[D3D12CommandData::Primary].baseEvent)
        {
          ID3D12GraphicsCommandList *list =
              m_Cmd.RerecordCmdList(cmdIds[c], D3D12CommandData::Primary);
          ResourceId partial = GetResID(list);
#if ENABLED(VERBOSE_PARTIAL_REPLAY)
          RDCDEBUG("Queue Submit partial replay of %llu at %u, using %llu", cmdIds[c], eid, partial);
#endif
          trimmedCmdIds.push_back(partial);
          trimmedCmds.push_back(Unwrap(list));
        }
        else if(m_Cmd.m_LastEventID >= end)
        {
#if ENABLED(VERBOSE_PARTIAL_REPLAY)
          RDCDEBUG("Queue Submit full replay %llu", cmdIds[c]);
#endif
          trimmedCmdIds.push_back(cmdIds[c]);
          trimmedCmds.push_back(Unwrap(GetResourceManager()->GetLiveAs<ID3D12CommandList>(cmdIds[c])));
        }
        else
        {
#if ENABLED(VERBOSE_PARTIAL_REPLAY)
          RDCDEBUG("Queue not submitting %llu", cmdIds[c]);
#endif
        }

        // 1 extra to account for the virtual end command list label (begin is accounted for
        // above)
        eid += 1 + m_Cmd.m_BakedCmdListInfo[cmdIds[c]].eventCount;
      }

      RDCASSERT(trimmedCmds.size() > 0);

#if ENABLED(SINGLE_FLUSH_VALIDATE)
      for(size_t i = 0; i < trimmedCmds.size(); i++)
      {
        real->ExecuteCommandLists(1, &trimmedCmds[i]);
        m_pDevice->GPUSync();
      }
#else
      real->ExecuteCommandLists((UINT)trimmedCmds.size(), &trimmedCmds[0]);
#endif

      for(uint32_t i = 0; i < trimmedCmdIds.size(); i++)
      {
        ResourceId cmd = trimmedCmdIds[i];
        m_pDevice->ApplyBarriers(m_Cmd.m_BakedCmdListInfo[cmd].barriers);
      }
    }
    else
    {
#if ENABLED(VERBOSE_PARTIAL_REPLAY)
      RDCDEBUG("Queue Submit full replay %u >= %u", m_Cmd.m_LastEventID, m_Cmd.m_RootEventID);
#endif

      ID3D12CommandList **unwrapped = new ID3D12CommandList *[numCmds];
      for(uint32_t i = 0; i < numCmds; i++)
        unwrapped[i] = Unwrap(cmds[i]);

#if ENABLED(SINGLE_FLUSH_VALIDATE)
      for(UINT i = 0; i < numCmds; i++)
      {
        real->ExecuteCommandLists(1, &unwrapped[i]);
        m_pDevice->GPUSync();
      }
#else
      real->ExecuteCommandLists(numCmds, unwrapped);
#endif

      SAFE_DELETE_ARRAY(unwrapped);

      for(uint32_t i = 0; i < numCmds; i++)
      {
        ResourceId cmd = GetResourceManager()->GetLiveID(cmdIds[i]);
        m_pDevice->ApplyBarriers(m_Cmd.m_BakedCmdListInfo[cmd].barriers);
      }
    }
  }

  SAFE_DELETE_ARRAY(cmds);

  return true;
}
Exemplo n.º 29
0
ReplayCreateStatus GL_CreateReplayDevice(const char *logfile, IReplayDriver **driver)
{
	RDCDEBUG("Creating an OpenGL replay device");

	if(glXCreateContextAttribsProc == NULL)
	{
		glXGetFuncProc = (PFNGLXGETPROCADDRESSPROC)dlsym(RTLD_NEXT, "glXGetProcAddress");
		glXDestroyCtxProc = (PFNGLXDESTROYCONTEXTPROC)dlsym(RTLD_NEXT, "glXDestroyContext");
		glXSwapProc = (PFNGLXSWAPBUFFERSPROC)dlsym(RTLD_NEXT, "glXSwapBuffers");
		glXChooseFBConfigProc = (PFNGLXCHOOSEFBCONFIGPROC)dlsym(RTLD_NEXT, "glXChooseFBConfig");
		glXCreatePbufferProc = (PFNGLXCREATEPBUFFERPROC)dlsym(RTLD_NEXT, "glXCreatePbuffer");
		glXDestroyPbufferProc = (PFNGLXDESTROYPBUFFERPROC)dlsym(RTLD_NEXT, "glXDestroyPbuffer");
		glXQueryDrawableProc = (PFNGLXQUERYDRAWABLEPROC)dlsym(RTLD_NEXT, "glXQueryDrawable");

		if(glXGetFuncProc == NULL || glXDestroyCtxProc == NULL ||
			 glXSwapProc == NULL || glXChooseFBConfigProc == NULL ||
			 glXCreatePbufferProc == NULL || glXDestroyPbufferProc == NULL ||
			 glXQueryDrawableProc == NULL)
		{
			RDCERR("Couldn't find required entry points, glXGetProcAddress glXDestroyContext glXSwapBuffers");
			return eReplayCreate_APIInitFailed;
		}

		glXCreateContextAttribsProc = (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetFuncProc((const GLubyte*)"glXCreateContextAttribsARB");
		glXMakeContextCurrentProc = (PFNGLXMAKECONTEXTCURRENTPROC)glXGetFuncProc((const GLubyte*)"glXMakeContextCurrent");

		if(glXCreateContextAttribsProc == NULL || glXMakeContextCurrentProc == NULL)
		{
			RDCERR("Couldn't get glx function addresses, glXCreateContextAttribsARB glXMakeContextCurrent");
			return eReplayCreate_APIInitFailed;
		}
	}

	GLInitParams initParams;
	RDCDriver driverType = RDC_OpenGL;
	string driverName = "OpenGL";
	if(logfile)
		RenderDoc::Inst().FillInitParams(logfile, driverType, driverName, (RDCInitParams *)&initParams);

	if(initParams.SerialiseVersion != GLInitParams::GL_SERIALISE_VERSION)
	{
		RDCERR("Incompatible OpenGL serialise version, expected %d got %d", GLInitParams::GL_SERIALISE_VERSION, initParams.SerialiseVersion);
		return eReplayCreate_APIIncompatibleVersion;
	}

	int attribs[64] = {0};
	int i=0;

	GLReplay::PreContextInitCounters();

	attribs[i++] = GLX_CONTEXT_MAJOR_VERSION_ARB;
	attribs[i++] = 4;
	attribs[i++] = GLX_CONTEXT_MINOR_VERSION_ARB;
	attribs[i++] = 3;
	attribs[i++] = GLX_CONTEXT_FLAGS_ARB;
	attribs[i++] = GLX_CONTEXT_DEBUG_BIT_ARB;
	attribs[i++] = GLX_CONTEXT_PROFILE_MASK_ARB;
	attribs[i++] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB;

	Display *dpy = XOpenDisplay(NULL);

	if(dpy == NULL)
	{
		RDCERR("Couldn't open default X display");
		return eReplayCreate_APIInitFailed;
	}

	// don't need to care about the fb config as we won't be using the default framebuffer (backbuffer)
	static int visAttribs[] = { 0 };
	int numCfgs = 0;
	GLXFBConfig *fbcfg = glXChooseFBConfigProc(dpy, DefaultScreen(dpy), visAttribs, &numCfgs);

	if(fbcfg == NULL)
	{
		XCloseDisplay(dpy);
		GLReplay::PostContextShutdownCounters();
		RDCERR("Couldn't choose default framebuffer config");
		return eReplayCreate_APIInitFailed;
	}

	GLXContext ctx = glXCreateContextAttribsProc(dpy, fbcfg[0], 0, true, attribs);

	if(ctx == NULL)
	{
		XFree(fbcfg);
		XCloseDisplay(dpy);
		GLReplay::PostContextShutdownCounters();
		RDCERR("Couldn't create 4.3 context - RenderDoc requires OpenGL 4.3 availability");
		return eReplayCreate_APIHardwareUnsupported;
	}

	// don't care about pbuffer properties for same reason as backbuffer
	int pbAttribs[] = { GLX_PBUFFER_WIDTH, 32, GLX_PBUFFER_HEIGHT, 32, 0 };

	GLXPbuffer pbuffer = glXCreatePbufferProc(dpy, fbcfg[0], pbAttribs);

	XFree(fbcfg);

	Bool res = glXMakeContextCurrentProc(dpy, pbuffer, pbuffer, ctx);

	if(!res)
	{
		glXDestroyPbufferProc(dpy, pbuffer);
		glXDestroyCtxProc(dpy, ctx);
		XFree(fbcfg);
		XCloseDisplay(dpy);
		GLReplay::PostContextShutdownCounters();
		RDCERR("Couldn't make pbuffer & context current");
		return eReplayCreate_APIInitFailed;
	}

	PFNGLGETINTEGERVPROC getInt = (PFNGLGETINTEGERVPROC)glXGetFuncProc((const GLubyte *)"glGetIntegerv");
	PFNGLGETSTRINGIPROC getStr = (PFNGLGETSTRINGIPROC)glXGetFuncProc((const GLubyte *)"glGetStringi");

	if(getInt == NULL || getStr == NULL)
	{
		RDCERR("Couldn't get glGetIntegerv (%p) or glGetStringi (%p) entry points", getInt, getStr);
		glXDestroyPbufferProc(dpy, pbuffer);
		glXDestroyCtxProc(dpy, ctx);
		XFree(fbcfg);
		XCloseDisplay(dpy);
		GLReplay::PostContextShutdownCounters();
		return eReplayCreate_APIInitFailed;
	}
	else
	{
		// eventually we want to emulate EXT_dsa on replay if it isn't present, but for
		// now we just require it.
		bool dsa = false;
		bool bufstorage = false;

		if(getStr)
			RDCLOG("Running GL replay on: %s / %s / %s", getStr(eGL_VENDOR), getStr(eGL_RENDERER), getStr(eGL_VERSION));

		GLint numExts = 0;
		getInt(eGL_NUM_EXTENSIONS, &numExts);
		for(GLint e=0; e < numExts; e++)
		{
			const char *ext = (const char *)getStri(eGL_EXTENSIONS, (GLuint)e);

			RDCLOG("Extension % 3d: %s", e, ext);

			if(!strcmp(ext, "GL_EXT_direct_state_access")) dsa = true;
			if(!strcmp(ext, "GL_ARB_buffer_storage")) bufstorage = true;
		}

		if(!dsa)
			RDCERR("RenderDoc requires EXT_direct_state_access availability, and it is not reported. Try updating your drivers.");

		if(!bufstorage)
			RDCERR("RenderDoc requires ARB_buffer_storage availability, and it is not reported. Try updating your drivers.");

		if(!dsa || !bufstorage)
		{
			glXDestroyPbufferProc(dpy, pbuffer);
			glXDestroyCtxProc(dpy, ctx);
			XFree(fbcfg);
			XCloseDisplay(dpy);
			GLReplay::PostContextShutdownCounters();
			return eReplayCreate_APIHardwareUnsupported;
		}
	}

	WrappedOpenGL *gl = new WrappedOpenGL(logfile, GetRealGLFunctions());
	gl->Initialise(initParams);

	RDCLOG("Created device.");
	GLReplay *replay = gl->GetReplay();
	replay->SetProxy(logfile == NULL);
	GLWindowingData data;
	data.dpy = dpy;
	data.ctx = ctx;
	data.wnd = pbuffer;
	replay->SetReplayData(data);

	*driver = (IReplayDriver *)replay;
	return eReplayCreate_Success;
}
Exemplo n.º 30
0
void WrappedID3D11DeviceContext::ReplayLog(LogState readType, uint32_t startEventID, uint32_t endEventID, bool partial)
{
	m_State = readType;

	m_DoStateVerify = true;

	D3D11ChunkType header = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false);
	RDCASSERT(header == CONTEXT_CAPTURE_HEADER);

	ResourceId id;
	m_pSerialiser->Serialise("context", id);

	WrappedID3D11DeviceContext *context = (WrappedID3D11DeviceContext *)m_pDevice->GetResourceManager()->GetLiveResource(id);
	
	RDCASSERT(WrappedID3D11DeviceContext::IsAlloc(context) && context == this);

	Serialise_BeginCaptureFrame(!partial);

	m_pSerialiser->PopContext(NULL, header);

	m_CurEvents.clear();
	
	if(m_State == EXECUTING)
	{
		FetchAPIEvent ev = GetEvent(startEventID);
		m_CurEventID = ev.eventID;
		m_pSerialiser->SetOffset(ev.fileOffset);
	}
	else if(m_State == READING)
	{
		m_CurEventID = 1;
	}

	if(m_State == EXECUTING)
	{
		ClearMaps();
		for(size_t i=0; i < m_pDevice->GetNumDeferredContexts(); i++)
		{
			WrappedID3D11DeviceContext *context = m_pDevice->GetDeferredContext(i);
			context->ClearMaps();
		}
	}

	m_pDevice->GetResourceManager()->MarkInFrame(true);

	while(1)
	{
		if(m_State == EXECUTING && m_CurEventID > endEventID)
		{
			// we can just break out if we've done all the events desired.
			break;
		}

		uint64_t offset = m_pSerialiser->GetOffset();

		D3D11ChunkType context = (D3D11ChunkType)m_pSerialiser->PushContext(NULL, 1, false);

		ProcessChunk(offset, context, false);
		
		RenderDoc::Inst().SetProgress(FileInitialRead, float(offset)/float(m_pSerialiser->GetSize()));
		
		// for now just abort after capture scope. Really we'd need to support multiple frames
		// but for now this will do.
		if(context == CONTEXT_CAPTURE_FOOTER)
			break;
		
		m_CurEventID++;
	}

	if(m_State == READING)
	{
		m_pDevice->GetFrameRecord().back().drawcallList = m_ParentDrawcall.Bake();

		m_ParentDrawcall.children.clear();

		int initialSkips = 0;

		for(auto it=WrappedID3D11Buffer::m_BufferList.begin(); it != WrappedID3D11Buffer::m_BufferList.end(); ++it)
			m_ResourceUses[it->first];

		for(auto it=WrappedID3D11Texture1D::m_TextureList.begin(); it != WrappedID3D11Texture1D::m_TextureList.end(); ++it)
			m_ResourceUses[it->first];
		for(auto it=WrappedID3D11Texture2D::m_TextureList.begin(); it != WrappedID3D11Texture2D::m_TextureList.end(); ++it)
			m_ResourceUses[it->first];
		for(auto it=WrappedID3D11Texture3D::m_TextureList.begin(); it != WrappedID3D11Texture3D::m_TextureList.end(); ++it)
			m_ResourceUses[it->first];

		for(auto it = m_ResourceUses.begin(); it != m_ResourceUses.end(); ++it)
		{
			ResourceId id = m_pDevice->GetResourceManager()->GetOriginalID(it->first);

			if(m_pDevice->GetResourceManager()->GetInitialContents(id) == NULL)
				continue;

			RDCDEBUG("Resource %llu", id);
			if(it->second.empty())
			{
				RDCDEBUG("Never used!");
				initialSkips++;
			}
			else
			{
				bool written = false;

				for(auto usit = it->second.begin(); usit != it->second.end(); ++usit)
				{
					ResourceUsage u = usit->usage;

					if(u == eUsage_SO ||
						u == eUsage_CS_UAV || u == eUsage_PS_UAV ||
						u == eUsage_OM_DSV || u == eUsage_OM_RTV)
					{
						written = true;
						break;
					}
				}

				if(written)
				{
					RDCDEBUG("Written in frame - needs initial state");
				}
				else
				{
					RDCDEBUG("Never written to in the frame");
					initialSkips++;
				}
			}
		}

		RDCDEBUG("Can skip %d initial states.", initialSkips);
	}

	m_pDevice->GetResourceManager()->MarkInFrame(false);

	m_State = READING;

	m_DoStateVerify = false;
}