1/**************************************************************************
2 * Copyright 2015 VMware, Inc.
3 * All Rights Reserved.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 *
25 **************************************************************************/
26
27#include <windows.h>
28
29#define WGL_WGLEXT_PROTOTYPES
30
31#include <GL/gl.h>
32#include <GL/wglext.h>
33
34#include "state_tracker/st_copytex.h"
35
36#include "pipe/p_defines.h"
37#include "pipe/p_screen.h"
38#include "pipe/p_state.h"
39
40#include "stw_icd.h"
41#include "stw_context.h"
42#include "stw_device.h"
43#include "stw_pixelformat.h"
44#include "stw_framebuffer.h"
45#include "stw_st.h"
46
47
48/** Translate a WGL buffer name to a GLenum */
49static GLenum
50translate_ibuffer(int iBuffer)
51{
52   switch (iBuffer) {
53   case WGL_FRONT_LEFT_ARB:
54      return GL_FRONT_LEFT;
55   case WGL_BACK_LEFT_ARB:
56      return GL_BACK_LEFT;
57   case WGL_FRONT_RIGHT_ARB:
58      return GL_FRONT_RIGHT;
59   case WGL_BACK_RIGHT_ARB:
60      return GL_BACK_RIGHT;
61   case WGL_AUX0_ARB:
62      return GL_AUX0;
63   default:
64      return GL_NONE;
65   }
66}
67
68
69/** Translate a WGL texture target type to a GLenum */
70static GLenum
71translate_target(unsigned textureTarget)
72{
73   switch (textureTarget) {
74   case WGL_TEXTURE_1D_ARB:
75      return GL_TEXTURE_1D;
76   case WGL_TEXTURE_2D_ARB:
77      return GL_TEXTURE_2D;
78   case WGL_TEXTURE_CUBE_MAP_ARB:
79      return GL_TEXTURE_CUBE_MAP;
80   case WGL_NO_TEXTURE_ARB:
81   default:
82      return GL_NONE;
83   }
84}
85
86
87/** Translate a WGL texture format to a GLenum */
88static GLenum
89translate_texture_format(unsigned wgl_format)
90{
91   switch (wgl_format) {
92   case WGL_TEXTURE_RGB_ARB:
93      return GL_RGB;
94   case WGL_TEXTURE_RGBA_ARB:
95      return GL_RGBA;
96   case WGL_NO_TEXTURE_ARB:
97   default:
98      return GL_NONE;
99   }
100}
101
102
103BOOL WINAPI
104wglBindTexImageARB(HPBUFFERARB hPbuffer, int iBuffer)
105{
106   HDC prevDrawable = stw_get_current_dc();
107   HDC dc;
108   struct stw_context *curctx = stw_current_context();
109   struct stw_framebuffer *fb;
110   GLenum texFormat, srcBuffer, target;
111   boolean retVal;
112   int pixelFormatSave;
113
114   /*
115    * Implementation notes:
116    * Ideally, we'd implement this function with the
117    * st_context_iface::teximage() function which replaces a specific
118    * texture image with a different resource (the pbuffer).
119    * The main problem however, is the pbuffer image is upside down relative
120    * to the texture image.
121    * Window system drawing surfaces (windows & pbuffers) are "top to bottom"
122    * while OpenGL texture images are "bottom to top".  One possible solution
123    * to this is to invert rendering to pbuffers (as we do for renderbuffers)
124    * but that could lead to other issues (and would require extensive
125    * testing).
126    *
127    * The simple alternative is to use a copy-based approach which copies the
128    * pbuffer image into the texture via glCopyTex[Sub]Image.  That's what
129    * we do here.
130    */
131
132   fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
133   if (!fb) {
134      debug_printf("Invalid pbuffer handle in wglBindTexImageARB()\n");
135      SetLastError(ERROR_INVALID_HANDLE);
136      return FALSE;
137   }
138
139   srcBuffer = translate_ibuffer(iBuffer);
140   if (srcBuffer == GL_NONE) {
141      debug_printf("Invalid buffer 0x%x in wglBindTexImageARB()\n", iBuffer);
142      SetLastError(ERROR_INVALID_DATA);
143      return FALSE;
144   }
145
146   target = translate_target(fb->textureTarget);
147   if (target == GL_NONE) {
148      debug_printf("no texture target in wglBindTexImageARB()\n");
149      return FALSE;
150   }
151
152   texFormat = translate_texture_format(fb->textureFormat);
153   if (texFormat == GL_NONE) {
154      debug_printf("no texture format in wglBindTexImageARB()\n");
155      return FALSE;
156   }
157
158   /*
159    * Bind the pbuffer surface so we can read/copy from it.
160    *
161    * Before we can call stw_make_current() we have to temporarily
162    * change the pbuffer's pixel format to match the context to avoid
163    * an error condition.  After the stw_make_current() we restore the
164    * buffer's pixel format.
165    */
166   pixelFormatSave = fb->iPixelFormat;
167   fb->iPixelFormat = curctx->iPixelFormat;
168   dc = wglGetPbufferDCARB(hPbuffer);
169   retVal = stw_make_current(dc, curctx->dhglrc);
170   fb->iPixelFormat = pixelFormatSave;
171   if (!retVal) {
172      debug_printf("stw_make_current(#1) failed in wglBindTexImageARB()\n");
173      wglReleasePbufferDCARB(hPbuffer, dc);
174      return FALSE;
175   }
176
177   st_copy_framebuffer_to_texture(srcBuffer, fb->width, fb->height,
178                                  target, fb->textureLevel,
179                                  fb->textureFace, texFormat);
180
181   /* rebind previous drawing surface */
182   retVal = stw_make_current(prevDrawable, curctx->dhglrc);
183   if (!retVal) {
184      debug_printf("stw_make_current(#2) failed in wglBindTexImageARB()\n");
185   }
186
187   wglReleasePbufferDCARB(hPbuffer, dc);
188
189   return retVal;
190}
191
192
193BOOL WINAPI
194wglReleaseTexImageARB(HPBUFFERARB hPbuffer, int iBuffer)
195{
196   struct stw_framebuffer *fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
197   GLenum srcBuffer;
198
199   /* nothing to do here, but we do error checking anyway */
200
201   if (!fb) {
202      debug_printf("Invalid pbuffer handle in wglReleaseTexImageARB()\n");
203      SetLastError(ERROR_INVALID_HANDLE);
204      return FALSE;
205   }
206
207   srcBuffer = translate_ibuffer(iBuffer);
208   if (srcBuffer == GL_NONE) {
209      debug_printf("Invalid buffer 0x%x in wglReleaseTexImageARB()\n", iBuffer);
210      SetLastError(ERROR_INVALID_DATA);
211      return FALSE;
212   }
213
214   return TRUE;
215}
216
217
218BOOL WINAPI
219wglSetPbufferAttribARB(HPBUFFERARB hPbuffer, const int *piAttribList)
220{
221   struct stw_framebuffer *fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
222   int face, i;
223
224   if (!fb) {
225      SetLastError(ERROR_INVALID_HANDLE);
226      return FALSE;
227   }
228
229   for (i = 0; piAttribList[i]; i += 2) {
230      switch (piAttribList[i]) {
231      case WGL_MIPMAP_LEVEL_ARB:
232         fb->textureLevel = piAttribList[i+1];
233         break;
234      case WGL_CUBE_MAP_FACE_ARB:
235         face = piAttribList[i+1];
236         if (face >= WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
237             face <= WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
238            fb->textureFace = face - WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
239         }
240         else {
241            debug_printf("Invalid cube face 0x%x in "
242                         "wglSetPbufferAttribARB()\n",
243                         piAttribList[i]);
244            SetLastError(ERROR_INVALID_DATA);
245            return FALSE;
246         }
247         break;
248      default:
249         debug_printf("Invalid attribute 0x%x in wglSetPbufferAttribARB()\n",
250                      piAttribList[i]);
251         SetLastError(ERROR_INVALID_DATA);
252         return FALSE;
253      }
254   }
255
256   return TRUE;
257}
258