Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}