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