st/wgl: check for NULL piAttribList in wglCreatePbufferARB()
[mesa.git] / src / gallium / state_trackers / wgl / stw_ext_pbuffer.c
index 424d8daccb3a2743ac1c84eee023cf6549e8878c..02ccb76e277a8e63a4b44952ccb823dd8f4a3101 100644 (file)
@@ -35,6 +35,8 @@
 #include "pipe/p_defines.h"
 #include "pipe/p_screen.h"
 
+#include "util/u_debug.h"
+
 #include "stw_device.h"
 #include "stw_pixelformat.h"
 #include "stw_framebuffer.h"
@@ -65,7 +67,7 @@ WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 
 
 HPBUFFERARB WINAPI
-wglCreatePbufferARB(HDC _hDC,
+wglCreatePbufferARB(HDC hCurrentDC,
                     int iPixelFormat,
                     int iWidth,
                     int iHeight,
@@ -81,8 +83,14 @@ wglCreatePbufferARB(HDC _hDC,
    RECT rect;
    HWND hWnd;
    HDC hDC;
-
-   info = stw_pixelformat_get_info(iPixelFormat);
+   int iDisplayablePixelFormat;
+   PIXELFORMATDESCRIPTOR pfd;
+   BOOL bRet;
+   int textureFormat = WGL_NO_TEXTURE_ARB;
+   int textureTarget = WGL_NO_TEXTURE_ARB;
+   BOOL textureMipmap = FALSE;
+
+   info = stw_pixelformat_get_info(iPixelFormat - 1);
    if (!info) {
       SetLastError(ERROR_INVALID_PIXEL_FORMAT);
       return 0;
@@ -93,15 +101,47 @@ wglCreatePbufferARB(HDC _hDC,
       return 0;
    }
 
-   for (piAttrib = piAttribList; *piAttrib; piAttrib++) {
-      switch (*piAttrib) {
-      case WGL_PBUFFER_LARGEST_ARB:
-         piAttrib++;
-         useLargest = *piAttrib;
-         break;
-      default:
-         SetLastError(ERROR_INVALID_DATA);
-         return 0;
+   if (piAttribList) {
+      for (piAttrib = piAttribList; *piAttrib; piAttrib++) {
+         switch (*piAttrib) {
+         case WGL_PBUFFER_LARGEST_ARB:
+            piAttrib++;
+            useLargest = *piAttrib;
+            break;
+          case WGL_TEXTURE_FORMAT_ARB:
+             /* WGL_ARB_render_texture */
+             piAttrib++;
+             textureFormat = *piAttrib;
+             if (textureFormat != WGL_TEXTURE_RGB_ARB &&
+                textureFormat != WGL_TEXTURE_RGBA_ARB &&
+                textureFormat != WGL_NO_TEXTURE_ARB) {
+                SetLastError(ERROR_INVALID_DATA);
+                return 0;
+             }
+             break;
+          case WGL_TEXTURE_TARGET_ARB:
+             /* WGL_ARB_render_texture */
+             piAttrib++;
+             textureTarget = *piAttrib;
+             if (textureTarget != WGL_TEXTURE_CUBE_MAP_ARB &&
+                 textureTarget != WGL_TEXTURE_1D_ARB &&
+                 textureTarget != WGL_TEXTURE_2D_ARB &&
+                 textureTarget != WGL_NO_TEXTURE_ARB) {
+                SetLastError(ERROR_INVALID_DATA);
+                return 0;
+             }
+             break;
+         case WGL_MIPMAP_TEXTURE_ARB:
+            /* WGL_ARB_render_texture */
+            piAttrib++;
+            textureMipmap = !!*piAttrib;
+            break;
+         default:
+            SetLastError(ERROR_INVALID_DATA);
+            debug_printf("wgl: Unsupported attribute 0x%x in %s\n",
+                         *piAttrib, __func__);
+            return 0;
+         }
       }
    }
 
@@ -204,13 +244,34 @@ wglCreatePbufferARB(HDC _hDC,
       return 0;
    }
 
-   SetPixelFormat(hDC, iPixelFormat, &info->pfd);
-
+   /*
+    * We can't pass non-displayable pixel formats to GDI, which is why we
+    * create the framebuffer object before calling SetPixelFormat().
+    */
    fb = stw_framebuffer_create(hDC, iPixelFormat);
    if (!fb) {
       SetLastError(ERROR_NO_SYSTEM_RESOURCES);
+      return NULL;
    }
 
+   fb->bPbuffer = TRUE;
+
+   /* WGL_ARB_render_texture fields */
+   fb->textureTarget = textureTarget;
+   fb->textureFormat = textureFormat;
+   fb->textureMipmap = textureMipmap;
+
+   iDisplayablePixelFormat = fb->iDisplayablePixelFormat;
+
+   stw_framebuffer_unlock(fb);
+
+   /*
+    * We need to set a displayable pixel format on the hidden window DC
+    * so that wglCreateContext and wglMakeCurrent are not overruled by GDI.
+    */
+   bRet = SetPixelFormat(hDC, iDisplayablePixelFormat, &pfd);
+   assert(bRet);
+
    return (HPBUFFERARB)fb;
 }
 
@@ -221,10 +282,14 @@ wglGetPbufferDCARB(HPBUFFERARB hPbuffer)
    struct stw_framebuffer *fb;
    HDC hDC;
 
-   fb = (struct stw_framebuffer *)hPbuffer;
+   if (!hPbuffer) {
+      SetLastError(ERROR_INVALID_HANDLE);
+      return NULL;
+   }
+
+   fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
 
    hDC = GetDC(fb->hWnd);
-   SetPixelFormat(hDC, fb->iPixelFormat, &fb->pfi->pfd);
 
    return hDC;
 }
@@ -236,7 +301,12 @@ wglReleasePbufferDCARB(HPBUFFERARB hPbuffer,
 {
    struct stw_framebuffer *fb;
 
-   fb = (struct stw_framebuffer *)hPbuffer;
+   if (!hPbuffer) {
+      SetLastError(ERROR_INVALID_HANDLE);
+      return 0;
+   }
+
+   fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
 
    return ReleaseDC(fb->hWnd, hDC);
 }
@@ -247,7 +317,12 @@ wglDestroyPbufferARB(HPBUFFERARB hPbuffer)
 {
    struct stw_framebuffer *fb;
 
-   fb = (struct stw_framebuffer *)hPbuffer;
+   if (!hPbuffer) {
+      SetLastError(ERROR_INVALID_HANDLE);
+      return FALSE;
+   }
+
+   fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
 
    /* This will destroy all our data */
    return DestroyWindow(fb->hWnd);
@@ -261,19 +336,40 @@ wglQueryPbufferARB(HPBUFFERARB hPbuffer,
 {
    struct stw_framebuffer *fb;
 
-   fb = (struct stw_framebuffer *)hPbuffer;
+   if (!hPbuffer) {
+      SetLastError(ERROR_INVALID_HANDLE);
+      return FALSE;
+   }
+
+   fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
 
    switch (iAttribute) {
    case WGL_PBUFFER_WIDTH_ARB:
       *piValue = fb->width;
       return TRUE;
    case WGL_PBUFFER_HEIGHT_ARB:
-      *piValue = fb->width;
+      *piValue = fb->height;
       return TRUE;
    case WGL_PBUFFER_LOST_ARB:
       /* We assume that no content is ever lost due to display mode change */
       *piValue = FALSE;
       return TRUE;
+   /* WGL_ARB_render_texture */
+   case WGL_TEXTURE_TARGET_ARB:
+      *piValue = fb->textureTarget;
+      return TRUE;
+   case WGL_TEXTURE_FORMAT_ARB:
+      *piValue = fb->textureFormat;
+      return TRUE;
+   case WGL_MIPMAP_TEXTURE_ARB:
+      *piValue = fb->textureMipmap;
+      return TRUE;
+   case WGL_MIPMAP_LEVEL_ARB:
+      *piValue = fb->textureLevel;
+      return TRUE;
+   case WGL_CUBE_MAP_FACE_ARB:
+      *piValue = fb->textureFace + WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
+      return TRUE;
    default:
       SetLastError(ERROR_INVALID_DATA);
       return FALSE;