| /************************************************************************** |
| * Copyright 2015 VMware, Inc. |
| * All Rights Reserved. |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining a |
| * copy of this software and associated documentation files (the |
| * "Software"), to deal in the Software without restriction, including |
| * without limitation the rights to use, copy, modify, merge, publish, |
| * distribute, sub license, and/or sell copies of the Software, and to |
| * permit persons to whom the Software is furnished to do so, subject to |
| * the following conditions: |
| * |
| * The above copyright notice and this permission notice (including the |
| * next paragraph) shall be included in all copies or substantial portions |
| * of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. |
| * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR |
| * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| * |
| **************************************************************************/ |
| |
| #include <windows.h> |
| |
| #define WGL_WGLEXT_PROTOTYPES |
| |
| #include <GL/gl.h> |
| #include <GL/wglext.h> |
| |
| #include "state_tracker/st_copytex.h" |
| |
| #include "pipe/p_defines.h" |
| #include "pipe/p_screen.h" |
| #include "pipe/p_state.h" |
| |
| #include "stw_icd.h" |
| #include "stw_context.h" |
| #include "stw_device.h" |
| #include "stw_pixelformat.h" |
| #include "stw_framebuffer.h" |
| #include "stw_st.h" |
| |
| |
| /** Translate a WGL buffer name to a GLenum */ |
| static GLenum |
| translate_ibuffer(int iBuffer) |
| { |
| switch (iBuffer) { |
| case WGL_FRONT_LEFT_ARB: |
| return GL_FRONT_LEFT; |
| case WGL_BACK_LEFT_ARB: |
| return GL_BACK_LEFT; |
| case WGL_FRONT_RIGHT_ARB: |
| return GL_FRONT_RIGHT; |
| case WGL_BACK_RIGHT_ARB: |
| return GL_BACK_RIGHT; |
| case WGL_AUX0_ARB: |
| return GL_AUX0; |
| default: |
| return GL_NONE; |
| } |
| } |
| |
| |
| /** Translate a WGL texture target type to a GLenum */ |
| static GLenum |
| translate_target(unsigned textureTarget) |
| { |
| switch (textureTarget) { |
| case WGL_TEXTURE_1D_ARB: |
| return GL_TEXTURE_1D; |
| case WGL_TEXTURE_2D_ARB: |
| return GL_TEXTURE_2D; |
| case WGL_TEXTURE_CUBE_MAP_ARB: |
| return GL_TEXTURE_CUBE_MAP; |
| case WGL_NO_TEXTURE_ARB: |
| default: |
| return GL_NONE; |
| } |
| } |
| |
| |
| /** Translate a WGL texture format to a GLenum */ |
| static GLenum |
| translate_texture_format(unsigned wgl_format) |
| { |
| switch (wgl_format) { |
| case WGL_TEXTURE_RGB_ARB: |
| return GL_RGB; |
| case WGL_TEXTURE_RGBA_ARB: |
| return GL_RGBA; |
| case WGL_NO_TEXTURE_ARB: |
| default: |
| return GL_NONE; |
| } |
| } |
| |
| |
| BOOL WINAPI |
| wglBindTexImageARB(HPBUFFERARB hPbuffer, int iBuffer) |
| { |
| HDC prevDrawable = stw_get_current_dc(); |
| HDC prevReadable = stw_get_current_read_dc(); |
| HDC dc; |
| struct stw_context *curctx = stw_current_context(); |
| struct stw_framebuffer *fb; |
| GLenum texFormat, srcBuffer, target; |
| boolean retVal; |
| int pixelFormatSave; |
| |
| /* |
| * Implementation notes: |
| * Ideally, we'd implement this function with the |
| * st_context_iface::teximage() function which replaces a specific |
| * texture image with a different resource (the pbuffer). |
| * The main problem however, is the pbuffer image is upside down relative |
| * to the texture image. |
| * Window system drawing surfaces (windows & pbuffers) are "top to bottom" |
| * while OpenGL texture images are "bottom to top". One possible solution |
| * to this is to invert rendering to pbuffers (as we do for renderbuffers) |
| * but that could lead to other issues (and would require extensive |
| * testing). |
| * |
| * The simple alternative is to use a copy-based approach which copies the |
| * pbuffer image into the texture via glCopyTex[Sub]Image. That's what |
| * we do here. |
| */ |
| |
| if (!curctx) { |
| debug_printf("No rendering context in wglBindTexImageARB()\n"); |
| SetLastError(ERROR_INVALID_OPERATION); |
| return FALSE; |
| } |
| |
| fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer); |
| if (!fb) { |
| debug_printf("Invalid pbuffer handle in wglBindTexImageARB()\n"); |
| SetLastError(ERROR_INVALID_HANDLE); |
| return FALSE; |
| } |
| |
| srcBuffer = translate_ibuffer(iBuffer); |
| if (srcBuffer == GL_NONE) { |
| debug_printf("Invalid buffer 0x%x in wglBindTexImageARB()\n", iBuffer); |
| SetLastError(ERROR_INVALID_DATA); |
| return FALSE; |
| } |
| |
| target = translate_target(fb->textureTarget); |
| if (target == GL_NONE) { |
| debug_printf("no texture target in wglBindTexImageARB()\n"); |
| return FALSE; |
| } |
| |
| texFormat = translate_texture_format(fb->textureFormat); |
| if (texFormat == GL_NONE) { |
| debug_printf("no texture format in wglBindTexImageARB()\n"); |
| return FALSE; |
| } |
| |
| /* |
| * Bind the pbuffer surface so we can read/copy from it. |
| * |
| * Before we can call stw_make_current() we have to temporarily |
| * change the pbuffer's pixel format to match the context to avoid |
| * an error condition. After the stw_make_current() we restore the |
| * buffer's pixel format. |
| */ |
| pixelFormatSave = fb->iPixelFormat; |
| fb->iPixelFormat = curctx->iPixelFormat; |
| dc = wglGetPbufferDCARB(hPbuffer); |
| retVal = stw_make_current(dc, dc, curctx->dhglrc); |
| fb->iPixelFormat = pixelFormatSave; |
| if (!retVal) { |
| debug_printf("stw_make_current(#1) failed in wglBindTexImageARB()\n"); |
| wglReleasePbufferDCARB(hPbuffer, dc); |
| return FALSE; |
| } |
| |
| st_copy_framebuffer_to_texture(srcBuffer, fb->width, fb->height, |
| target, fb->textureLevel, |
| fb->textureFace, texFormat); |
| |
| /* rebind previous drawing surface */ |
| retVal = stw_make_current(prevDrawable, prevReadable, curctx->dhglrc); |
| if (!retVal) { |
| debug_printf("stw_make_current(#2) failed in wglBindTexImageARB()\n"); |
| } |
| |
| wglReleasePbufferDCARB(hPbuffer, dc); |
| |
| return retVal; |
| } |
| |
| |
| BOOL WINAPI |
| wglReleaseTexImageARB(HPBUFFERARB hPbuffer, int iBuffer) |
| { |
| struct stw_framebuffer *fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer); |
| GLenum srcBuffer; |
| |
| /* nothing to do here, but we do error checking anyway */ |
| |
| if (!fb) { |
| debug_printf("Invalid pbuffer handle in wglReleaseTexImageARB()\n"); |
| SetLastError(ERROR_INVALID_HANDLE); |
| return FALSE; |
| } |
| |
| srcBuffer = translate_ibuffer(iBuffer); |
| if (srcBuffer == GL_NONE) { |
| debug_printf("Invalid buffer 0x%x in wglReleaseTexImageARB()\n", iBuffer); |
| SetLastError(ERROR_INVALID_DATA); |
| return FALSE; |
| } |
| |
| return TRUE; |
| } |
| |
| |
| BOOL WINAPI |
| wglSetPbufferAttribARB(HPBUFFERARB hPbuffer, const int *piAttribList) |
| { |
| struct stw_framebuffer *fb = stw_framebuffer_from_HPBUFFERARB(hPbuffer); |
| int face, i; |
| |
| if (!fb) { |
| SetLastError(ERROR_INVALID_HANDLE); |
| return FALSE; |
| } |
| |
| for (i = 0; piAttribList[i]; i += 2) { |
| switch (piAttribList[i]) { |
| case WGL_MIPMAP_LEVEL_ARB: |
| fb->textureLevel = piAttribList[i+1]; |
| break; |
| case WGL_CUBE_MAP_FACE_ARB: |
| face = piAttribList[i+1]; |
| if (face >= WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB && |
| face <= WGL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB) { |
| fb->textureFace = face - WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB; |
| } |
| else { |
| debug_printf("Invalid cube face 0x%x in " |
| "wglSetPbufferAttribARB()\n", |
| piAttribList[i]); |
| SetLastError(ERROR_INVALID_DATA); |
| return FALSE; |
| } |
| break; |
| default: |
| debug_printf("Invalid attribute 0x%x in wglSetPbufferAttribARB()\n", |
| piAttribList[i]); |
| SetLastError(ERROR_INVALID_DATA); |
| return FALSE; |
| } |
| } |
| |
| return TRUE; |
| } |