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 "gldrv.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   struct stw_context *curctx = stw_current_context();
107   struct stw_framebuffer *fb, *old_fb, *old_fbRead;
108   GLenum texFormat, srcBuffer, target;
109   boolean retVal;
110   int pixelFormatSave;
111
112   /*
113    * Implementation notes:
114    * Ideally, we'd implement this function with the
115    * st_context_iface::teximage() function which replaces a specific
116    * texture image with a different resource (the pbuffer).
117    * The main problem however, is the pbuffer image is upside down relative
118    * to the texture image.
119    * Window system drawing surfaces (windows & pbuffers) are "top to bottom"
120    * while OpenGL texture images are "bottom to top".  One possible solution
121    * to this is to invert rendering to pbuffers (as we do for renderbuffers)
122    * but that could lead to other issues (and would require extensive
123    * testing).
124    *
125    * The simple alternative is to use a copy-based approach which copies the
126    * pbuffer image into the texture via glCopyTex[Sub]Image.  That's what
127    * we do here.
128    */
129
130   if (!curctx) {
131      debug_printf("No rendering context in wglBindTexImageARB()\n");
132      SetLastError(ERROR_INVALID_OPERATION);
133      return FALSE;
134   }
135
136   fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
137   if (!fb) {
138      debug_printf("Invalid pbuffer handle in wglBindTexImageARB()\n");
139      SetLastError(ERROR_INVALID_HANDLE);
140      return FALSE;
141   }
142
143   srcBuffer = translate_ibuffer(iBuffer);
144   if (srcBuffer == GL_NONE) {
145      debug_printf("Invalid buffer 0x%x in wglBindTexImageARB()\n", iBuffer);
146      SetLastError(ERROR_INVALID_DATA);
147      return FALSE;
148   }
149
150   target = translate_target(fb->textureTarget);
151   if (target == GL_NONE) {
152      debug_printf("no texture target in wglBindTexImageARB()\n");
153      return FALSE;
154   }
155
156   texFormat = translate_texture_format(fb->textureFormat);
157   if (texFormat == GL_NONE) {
158      debug_printf("no texture format in wglBindTexImageARB()\n");
159      return FALSE;
160   }
161
162   old_fb = curctx->current_framebuffer;
163   old_fbRead = curctx->current_read_framebuffer;
164
165   /*
166    * Bind the pbuffer surface so we can read/copy from it.
167    *
168    * Before we can call stw_make_current() we have to temporarily
169    * change the pbuffer's pixel format to match the context to avoid
170    * an error condition.  After the stw_make_current() we restore the
171    * buffer's pixel format.
172    */
173   pixelFormatSave = fb->iPixelFormat;
174   fb->iPixelFormat = curctx->iPixelFormat;
175   retVal = stw_make_current(fb, fb, curctx);
176   fb->iPixelFormat = pixelFormatSave;
177   if (!retVal) {
178      debug_printf("stw_make_current(#1) failed in wglBindTexImageARB()\n");
179      return FALSE;
180   }
181
182   st_copy_framebuffer_to_texture(srcBuffer, fb->width, fb->height,
183                                  target, fb->textureLevel,
184                                  fb->textureFace, texFormat);
185
186   /* rebind previous drawing surface */
187   retVal = stw_make_current(old_fb, old_fbRead, curctx);
188   if (!retVal) {
189      debug_printf("stw_make_current(#2) failed in wglBindTexImageARB()\n");
190   }
191
192   return retVal;
193}
194
195
196BOOL WINAPI
197wglReleaseTexImageARB(HPBUFFERARB hPbuffer, int iBuffer)
198{
199   struct stw_framebuffer *fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
200   GLenum srcBuffer;
201
202   /* nothing to do here, but we do error checking anyway */
203
204   if (!fb) {
205      debug_printf("Invalid pbuffer handle in wglReleaseTexImageARB()\n");
206      SetLastError(ERROR_INVALID_HANDLE);
207      return FALSE;
208   }
209
210   srcBuffer = translate_ibuffer(iBuffer);
211   if (srcBuffer == GL_NONE) {
212      debug_printf("Invalid buffer 0x%x in wglReleaseTexImageARB()\n", iBuffer);
213      SetLastError(ERROR_INVALID_DATA);
214      return FALSE;
215   }
216
217   return TRUE;
218}
219
220
221BOOL WINAPI
222wglSetPbufferAttribARB(HPBUFFERARB hPbuffer, const int *piAttribList)
223{
224   struct stw_framebuffer *fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer);
225   int face, i;
226
227   if (!fb) {
228      SetLastError(ERROR_INVALID_HANDLE);
229      return FALSE;
230   }
231
232   for (i = 0; piAttribList[i]; i += 2) {
233      switch (piAttribList[i]) {
234      case WGL_MIPMAP_LEVEL_ARB:
235         fb->textureLevel = piAttribList[i+1];
236         break;
237      case WGL_CUBE_MAP_FACE_ARB:
238         face = piAttribList[i+1];
239         if (face >= WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB &&
240             face <= WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) {
241            fb->textureFace = face - WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB;
242         }
243         else {
244            debug_printf("Invalid cube face 0x%x in "
245                         "wglSetPbufferAttribARB()\n",
246                         piAttribList[i]);
247            SetLastError(ERROR_INVALID_DATA);
248            return FALSE;
249         }
250         break;
251      default:
252         debug_printf("Invalid attribute 0x%x in wglSetPbufferAttribARB()\n",
253                      piAttribList[i]);
254         SetLastError(ERROR_INVALID_DATA);
255         return FALSE;
256      }
257   }
258
259   return TRUE;
260}
261