/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS * FILE: dll/opengl/opengl32/swimpl.c * PURPOSE: OpenGL32 DLL, opengl software implementation */ #include "opengl32.h" /* MESA includes */ #include
#include
#include
#include
#include
#include #include #include #include #include #include #include WINE_DEFAULT_DEBUG_CHANNEL(opengl32); #define WIDTH_BYTES_ALIGN32(cx, bpp) ((((cx) * (bpp) + 31) & ~31) >> 3) static const struct { gl_format mesa; BYTE color_bits; BYTE red_bits, red_shift; DWORD red_mask; BYTE green_bits, green_shift; DWORD green_mask; BYTE blue_bits, blue_shift; DWORD blue_mask; BYTE alpha_bits, alpha_shift; DWORD alpha_mask; BYTE accum_bits; BYTE depth_bits; BYTE stencil_bits; DWORD bmp_compression; } pixel_formats[] = { { MESA_FORMAT_ARGB8888, 32, 8, 8, 0x00FF0000, 8, 16, 0x0000FF00, 8, 24, 0x000000FF, 8, 0, 0xFF000000, 16, 32, 8, BI_BITFIELDS }, { MESA_FORMAT_ARGB8888, 32, 8, 8, 0x00FF0000, 8, 16, 0x0000FF00, 8, 24, 0x000000FF, 8, 0, 0xFF000000, 16, 16, 8, BI_BITFIELDS }, { MESA_FORMAT_RGBA8888_REV, 32, 8, 8, 0x000000FF, 8, 16, 0x0000FF00, 8, 24, 0x00FF0000, 8, 0, 0xFF000000, 16, 32, 8, BI_BITFIELDS }, { MESA_FORMAT_RGBA8888_REV, 32, 8, 8, 0x000000FF, 8, 16, 0x0000FF00, 8, 24, 0x00FF0000, 8, 0, 0xFF000000, 16, 16, 8, BI_BITFIELDS }, { MESA_FORMAT_RGBA8888, 32, 8, 0, 0xFF000000, 8, 8, 0x00FF0000, 8, 16, 0x0000FF00, 8, 24, 0x000000FF, 16, 32, 8, BI_BITFIELDS }, { MESA_FORMAT_RGBA8888, 32, 8, 0, 0xFF000000, 8, 8, 0x00FF0000, 8, 16, 0x0000FF00, 8, 24, 0x000000FF, 16, 16, 8, BI_BITFIELDS }, { MESA_FORMAT_ARGB8888_REV, 32, 8, 16, 0x0000FF00, 8, 8, 0x00FF0000, 8, 0, 0xFF000000, 8, 24, 0x000000FF, 16, 32, 8, BI_BITFIELDS }, { MESA_FORMAT_ARGB8888_REV, 32, 8, 16, 0x0000FF00, 8, 8, 0x00FF0000, 8, 0, 0xFF000000, 8, 24, 0x000000FF, 16, 16, 8, BI_BITFIELDS }, { MESA_FORMAT_RGB888, 24, 8, 0, 0x00000000, 8, 8, 0x00000000, 8, 16, 0x00000000, 0, 0, 0x00000000, 16, 32, 8, BI_RGB }, { MESA_FORMAT_RGB888, 24, 8, 0, 0x00000000, 8, 8, 0x00000000, 8, 16, 0x00000000, 0, 0, 0x00000000, 16, 16, 8, BI_RGB }, // { MESA_FORMAT_BGR888, 24, 8, 16, 8, 8, 8, 0, 0, 0, 16, 32, 8 }, // { MESA_FORMAT_BGR888, 24, 8, 16, 8, 8, 8, 0, 0, 0, 16, 16, 8 }, { MESA_FORMAT_RGB565, 16, 5, 0, 0x0000F800, 6, 5, 0x000007E0, 5, 11, 0x0000001F, 0, 0, 0x00000000, 16, 32, 8, BI_BITFIELDS }, { MESA_FORMAT_RGB565, 16, 5, 0, 0x0000F800, 6, 5, 0x000007E0, 5, 11, 0x0000001F, 0, 0, 0x00000000, 16, 16, 8, BI_BITFIELDS }, }; #define SW_BACK_RENDERBUFFER_CLASS 0x8911 #define SW_FRONT_RENDERBUFFER_CLASS 0x8910 struct sw_front_renderbuffer { struct swrast_renderbuffer swrast; HDC hdcmem; GLuint x, y, w, h; HBITMAP hbmp; BOOL write; }; #define SW_FB_DOUBLEBUFFERED 0x1 #define SW_FB_DIRTY_SIZE 0x2 struct sw_framebuffer { HDC hdc; INT sw_format; UINT format_index; DWORD flags; /* The mesa objects */ struct gl_config *gl_visual; /* Describes the buffers */ struct gl_framebuffer *gl_buffer; /* The mesa representation of frame buffer */ struct sw_front_renderbuffer frontbuffer; struct swrast_renderbuffer backbuffer; /* The bitmapi info we will use for rendering to display */ BITMAPINFO bmi; }; struct sw_context { struct gl_context mesa; /* Base class - this must be first */ /* This is to keep track of the size of the front buffer */ HHOOK hook; /* Framebuffer currently owning the context */ struct sw_framebuffer framebuffer; }; /* mesa opengl32 "driver" specific */ static const GLubyte * sw_get_string( struct gl_context *ctx, GLenum name ) { (void) ctx; if(name == GL_RENDERER) { static const GLubyte renderer[] = { 'R','e','a','c','t','O','S',' ', 'S','o','f','t','w','a','r','e',' ', 'I','m','p','l','e','m','e','n','t','a','t','i','o','n',0 }; return renderer; } /* Don't claim to support the fancy extensions that mesa supports, they will be slow anyway */ if(name == GL_EXTENSIONS) { static const GLubyte extensions[] = { 0 }; return extensions; } return NULL; } static void sw_update_state( struct gl_context *ctx, GLuint new_state ) { /* easy - just propagate */ _swrast_InvalidateState( ctx, new_state ); _swsetup_InvalidateState( ctx, new_state ); _tnl_InvalidateState( ctx, new_state ); _vbo_InvalidateState( ctx, new_state ); } /* Renderbuffer routines */ static GLboolean sw_bb_renderbuffer_storage(struct gl_context* ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); struct sw_framebuffer* fb = CONTAINING_RECORD(srb, struct sw_framebuffer, backbuffer); UINT widthBytes = WIDTH_BYTES_ALIGN32(width, pixel_formats[fb->format_index].color_bits); srb->Base.Format = pixel_formats[fb->format_index].mesa; if(srb->Buffer) srb->Buffer = HeapReAlloc(GetProcessHeap(), 0, srb->Buffer, widthBytes*height); else srb->Buffer = HeapAlloc(GetProcessHeap(), 0, widthBytes*height); if(!srb->Buffer) { srb->Base.Format = MESA_FORMAT_NONE; return GL_FALSE; } srb->Base.Width = width; srb->Base.Height = height; srb->RowStride = widthBytes; return GL_TRUE; } static void sw_bb_renderbuffer_delete(struct gl_renderbuffer *rb) { struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); if (srb->Buffer) { HeapFree(GetProcessHeap(), 0, srb->Buffer); srb->Buffer = NULL; } } static void sw_fb_renderbuffer_delete(struct gl_renderbuffer *rb) { struct sw_front_renderbuffer* srb = (struct sw_front_renderbuffer*)rb; if (srb->hbmp) { srb->hbmp = SelectObject(srb->hdcmem, srb->hbmp); DeleteDC(srb->hdcmem); DeleteObject(srb->hbmp); srb->hdcmem = NULL; srb->hbmp = NULL; srb->swrast.Buffer = NULL; } } static GLboolean sw_fb_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { struct sw_front_renderbuffer* srb = (struct sw_front_renderbuffer*)rb; struct sw_framebuffer* fb = CONTAINING_RECORD(srb, struct sw_framebuffer, frontbuffer); HDC hdc = IntGetCurrentDC(); /* Don't bother if the size doesn't change */ if(rb->Width == width && rb->Height == height) return GL_TRUE; /* Delete every objects which could have been used before */ sw_fb_renderbuffer_delete(&srb->swrast.Base); /* So the app wants to use the frontbuffer, allocate a DIB for it */ srb->hbmp = CreateDIBSection( hdc, &fb->bmi, DIB_RGB_COLORS, (void**)&srb->swrast.Buffer, NULL, 0); if(!srb->hbmp) { ERR("Failed to create the DIB section for the front buffer, %lu.\n", GetLastError()); return GL_FALSE; } /* Create the DC and attach the DIB section to it */ srb->hdcmem = CreateCompatibleDC(hdc); assert(srb->hdcmem != NULL); srb->hbmp = SelectObject(srb->hdcmem, srb->hbmp); assert(srb->hbmp != NULL); /* Set formats, width and height */ srb->swrast.Base.Format = pixel_formats[fb->format_index].mesa; srb->swrast.Base.Width = width; srb->swrast.Base.Height = height; return GL_TRUE; } static void sw_init_renderbuffers(struct sw_framebuffer *fb) { _mesa_init_renderbuffer(&fb->frontbuffer.swrast.Base, 0); fb->frontbuffer.swrast.Base.ClassID = SW_FRONT_RENDERBUFFER_CLASS; fb->frontbuffer.swrast.Base.AllocStorage = sw_fb_renderbuffer_storage; fb->frontbuffer.swrast.Base.Delete = sw_fb_renderbuffer_delete; fb->frontbuffer.swrast.Base.InternalFormat = GL_RGBA; fb->frontbuffer.swrast.Base._BaseFormat = GL_RGBA; _mesa_remove_renderbuffer(fb->gl_buffer, BUFFER_FRONT_LEFT); _mesa_add_renderbuffer(fb->gl_buffer, BUFFER_FRONT_LEFT, &fb->frontbuffer.swrast.Base); if(fb->flags & SW_FB_DOUBLEBUFFERED) { _mesa_init_renderbuffer(&fb->backbuffer.Base, 0); fb->backbuffer.Base.ClassID = SW_BACK_RENDERBUFFER_CLASS; fb->backbuffer.Base.AllocStorage = sw_bb_renderbuffer_storage; fb->backbuffer.Base.Delete = sw_bb_renderbuffer_delete; fb->backbuffer.Base.InternalFormat = GL_RGBA; fb->backbuffer.Base._BaseFormat = GL_RGBA; _mesa_remove_renderbuffer(fb->gl_buffer, BUFFER_BACK_LEFT); _mesa_add_renderbuffer(fb->gl_buffer, BUFFER_BACK_LEFT, &fb->backbuffer.Base); } } static void sw_MapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint x, GLuint y, GLuint w, GLuint h, GLbitfield mode, GLubyte **mapOut, GLint *rowStrideOut) { if(rb->ClassID == SW_FRONT_RENDERBUFFER_CLASS) { /* This is our front buffer */ struct sw_front_renderbuffer* srb = (struct sw_front_renderbuffer*)rb; struct sw_framebuffer* fb = CONTAINING_RECORD(srb, struct sw_framebuffer, frontbuffer); /* Set the stride */ *rowStrideOut = WIDTH_BYTES_ALIGN32(rb->Width, pixel_formats[fb->format_index].color_bits); /* Remember where we "mapped" */ srb->x = x; srb->y = y; srb->w = w; srb->h = h; /* Remember if we should write it later */ srb->write = !!(mode & GL_MAP_WRITE_BIT); /* Get the bits, if needed */ if(mode & GL_MAP_READ_BIT) { BitBlt(srb->hdcmem, srb->x, srb->y, srb->w, srb->h, IntGetCurrentDC(), srb->x, srb->y, SRCCOPY); } /* And return it */ *mapOut = (BYTE*)srb->swrast.Buffer + *rowStrideOut*y + x*pixel_formats[fb->format_index].color_bits/8; return; } if(rb->ClassID == SW_BACK_RENDERBUFFER_CLASS) { /* This is our front buffer */ struct swrast_renderbuffer* srb = (struct swrast_renderbuffer*)rb; const GLuint bpp = _mesa_get_format_bytes(rb->Format); /* Set the stride */ *rowStrideOut = srb->RowStride; *mapOut = (BYTE*)srb->Buffer + srb->RowStride*y + x*bpp; return; } /* Let mesa rasterizer take care of this */ _swrast_map_soft_renderbuffer(ctx, rb, x, y, w, h, mode, mapOut, rowStrideOut); } static void sw_UnmapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb) { if (rb->ClassID== SW_FRONT_RENDERBUFFER_CLASS) { /* This is our front buffer */ struct sw_front_renderbuffer* srb = (struct sw_front_renderbuffer*)rb; if(srb->write) { /* Copy the bits to our display */ BitBlt(IntGetCurrentDC(), srb->x, srb->y, srb->w, srb->h, srb->hdcmem, srb->x, srb->y, SRCCOPY); srb->write = FALSE; } return; } if(rb->ClassID == SW_BACK_RENDERBUFFER_CLASS) return; /* nothing to do */ /* Let mesa rasterizer take care of this */ _swrast_unmap_soft_renderbuffer(ctx, rb); } /* WGL <-> mesa glue */ static UINT index_from_format(struct wgl_dc_data* dc_data, INT format, BOOL* doubleBuffered) { UINT index; INT nb_win_compat = 0, start_win_compat = 0; HDC hdc; INT bpp; *doubleBuffered = FALSE; if(!(dc_data->flags & WGL_DC_OBJ_DC)) return format - 1; /* OBJ_MEMDC, not double buffered */ hdc = GetDC(dc_data->owner.hwnd); /* Find the window compatible formats */ bpp = GetDeviceCaps(hdc, BITSPIXEL); for(index = 0; indexowner.hwnd, hdc); /* Double buffered format */ if(format < (start_win_compat + nb_win_compat)) { if(format >= start_win_compat) *doubleBuffered = TRUE; return format-1; } /* Shift */ return format - nb_win_compat - 1; } INT sw_DescribePixelFormat(HDC hdc, INT format, UINT size, PIXELFORMATDESCRIPTOR* descr) { UINT index; INT nb_win_compat = 0, start_win_compat = 0; INT ret = sizeof(pixel_formats)/sizeof(pixel_formats[0]); if (GetObjectType(hdc) == OBJ_DC) { /* Find the window compatible formats */ INT bpp = GetDeviceCaps(hdc, BITSPIXEL); for (index = 0; index < sizeof(pixel_formats)/sizeof(pixel_formats[0]); index++) { if (pixel_formats[index].color_bits == bpp) { if (!start_win_compat) start_win_compat = index+1; nb_win_compat++; } } /* Add the double buffered formats */ ret += nb_win_compat; } index = (UINT)format - 1; if(!descr) return ret; if((format > ret) || (size != sizeof(*descr))) return 0; /* Set flags */ descr->dwFlags = PFD_SUPPORT_GDI | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP | PFD_GENERIC_FORMAT; /* See if this is a format compatible with the window */ if(format >= start_win_compat && format < (start_win_compat + nb_win_compat*2) ) { /* It is */ descr->dwFlags |= PFD_DRAW_TO_WINDOW; /* See if this should be double buffered */ if(format < (start_win_compat + nb_win_compat)) { /* No GDI, no bitmap */ descr->dwFlags &= ~(PFD_SUPPORT_GDI | PFD_DRAW_TO_BITMAP); descr->dwFlags |= PFD_DOUBLEBUFFER; } } /* Normalize the index */ if(format >= start_win_compat + nb_win_compat) index -= nb_win_compat; /* Fill the rest of the structure */ descr->nSize = sizeof(*descr); descr->nVersion = 1; descr->iPixelType = PFD_TYPE_RGBA; descr->cColorBits = pixel_formats[index].color_bits; descr->cRedBits = pixel_formats[index].red_bits; descr->cRedShift = pixel_formats[index].red_shift; descr->cGreenBits = pixel_formats[index].green_bits; descr->cGreenShift = pixel_formats[index].green_shift; descr->cBlueBits = pixel_formats[index].blue_bits; descr->cBlueShift = pixel_formats[index].blue_shift; descr->cAlphaBits = pixel_formats[index].alpha_bits; descr->cAlphaShift = pixel_formats[index].alpha_shift; descr->cAccumBits = pixel_formats[index].accum_bits; descr->cAccumRedBits = pixel_formats[index].accum_bits / 4; descr->cAccumGreenBits = pixel_formats[index].accum_bits / 4; descr->cAccumBlueBits = pixel_formats[index].accum_bits / 4; descr->cAccumAlphaBits = pixel_formats[index].accum_bits / 4; descr->cDepthBits = pixel_formats[index].depth_bits; descr->cStencilBits = pixel_formats[index].stencil_bits; descr->cAuxBuffers = 0; descr->iLayerType = PFD_MAIN_PLANE; return ret; } BOOL sw_SetPixelFormat(HDC hdc, struct wgl_dc_data* dc_data, INT format) { struct sw_framebuffer* fb; BOOL doubleBuffered; assert(dc_data->sw_data == NULL); /* So, someone is crazy enough to ask for sw implementation. Announce it. */ TRACE("OpenGL software implementation START!\n"); /* allocate our structure */ fb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(struct sw_framebuffer, bmi.bmiColors[3])); if(!fb) { ERR("HeapAlloc FAILED!\n"); return FALSE; } /* Get the format index */ fb->format_index = index_from_format(dc_data, format, &doubleBuffered); TRACE("Using format %u - double buffered: %x.\n", fb->format_index, doubleBuffered); fb->flags = doubleBuffered ? SW_FB_DOUBLEBUFFERED : 0; /* Set the bitmap info describing the framebuffer */ fb->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); fb->bmi.bmiHeader.biPlanes = 1; fb->bmi.bmiHeader.biBitCount = pixel_formats[fb->format_index].color_bits; fb->bmi.bmiHeader.biCompression = pixel_formats[fb->format_index].bmp_compression; fb->bmi.bmiHeader.biSizeImage = 0; fb->bmi.bmiHeader.biXPelsPerMeter = 0; fb->bmi.bmiHeader.biYPelsPerMeter = 0; fb->bmi.bmiHeader.biClrUsed = 0; fb->bmi.bmiHeader.biClrImportant = 0; *((DWORD*)&fb->bmi.bmiColors[0]) = pixel_formats[fb->format_index].red_mask; *((DWORD*)&fb->bmi.bmiColors[1]) = pixel_formats[fb->format_index].green_mask; *((DWORD*)&fb->bmi.bmiColors[2]) = pixel_formats[fb->format_index].blue_mask; /* Save the HDC */ fb->hdc = hdc; /* Allocate the visual structure describing the format */ fb->gl_visual = _mesa_create_visual( !!(fb->flags & SW_FB_DOUBLEBUFFERED), GL_FALSE, /* No stereoscopic support */ pixel_formats[fb->format_index].red_bits, pixel_formats[fb->format_index].green_bits, pixel_formats[fb->format_index].blue_bits, pixel_formats[fb->format_index].alpha_bits, pixel_formats[fb->format_index].depth_bits, pixel_formats[fb->format_index].stencil_bits, pixel_formats[fb->format_index].accum_bits, pixel_formats[fb->format_index].accum_bits, pixel_formats[fb->format_index].accum_bits, pixel_formats[fb->format_index].alpha_bits ? pixel_formats[fb->format_index].accum_bits : 0); if(!fb->gl_visual) { ERR("Failed to allocate a GL visual.\n"); HeapFree(GetProcessHeap(), 0, fb); return FALSE; } /* Allocate the framebuffer structure */ fb->gl_buffer = _mesa_create_framebuffer(fb->gl_visual); if (!fb->gl_buffer) { ERR("Failed to allocate the mesa framebuffer structure.\n"); _mesa_destroy_visual( fb->gl_visual ); HeapFree(GetProcessHeap(), 0, fb); return FALSE; } /* Add the depth/stencil/accum buffers */ _swrast_add_soft_renderbuffers(fb->gl_buffer, GL_FALSE, /* color */ fb->gl_visual->haveDepthBuffer, fb->gl_visual->haveStencilBuffer, fb->gl_visual->haveAccumBuffer, GL_FALSE, /* alpha */ GL_FALSE /* aux */ ); /* Initialize our render buffers */ sw_init_renderbuffers(fb); /* Everything went fine */ dc_data->sw_data = fb; return TRUE; } DHGLRC sw_CreateContext(struct wgl_dc_data* dc_data) { struct sw_context* sw_ctx; struct sw_framebuffer* fb = dc_data->sw_data; struct dd_function_table mesa_drv_functions; TNLcontext *tnl; /* We use the mesa memory routines for this function */ sw_ctx = CALLOC_STRUCT(sw_context); if(!sw_ctx) return NULL; /* Set mesa default functions */ _mesa_init_driver_functions(&mesa_drv_functions); /* Override */ mesa_drv_functions.GetString = sw_get_string; mesa_drv_functions.UpdateState = sw_update_state; mesa_drv_functions.GetBufferSize = NULL; /* Initialize the context */ if(!_mesa_initialize_context(&sw_ctx->mesa, fb->gl_visual, NULL, &mesa_drv_functions, (void *) sw_ctx)) { ERR("Failed to initialize the mesa context.\n"); free(sw_ctx); return NULL; } /* Initialize the "meta driver" */ _mesa_meta_init(&sw_ctx->mesa); /* Initialize helpers */ if(!_swrast_CreateContext(&sw_ctx->mesa) || !_vbo_CreateContext(&sw_ctx->mesa) || !_tnl_CreateContext(&sw_ctx->mesa) || !_swsetup_CreateContext(&sw_ctx->mesa)) { ERR("Failed initializing helpers.\n"); _mesa_free_context_data(&sw_ctx->mesa); free(sw_ctx); return NULL; } /* Wake up! */ _swsetup_Wakeup(&sw_ctx->mesa); /* Use TnL defaults */ tnl = TNL_CONTEXT(&sw_ctx->mesa); tnl->Driver.RunPipeline = _tnl_run_pipeline; /* To map the display into user memory */ sw_ctx->mesa.Driver.MapRenderbuffer = sw_MapRenderbuffer; sw_ctx->mesa.Driver.UnmapRenderbuffer = sw_UnmapRenderbuffer; return (DHGLRC)sw_ctx; } BOOL sw_DeleteContext(DHGLRC dhglrc) { struct sw_context* sw_ctx = (struct sw_context*)dhglrc; /* Those get clobbered by _mesa_free_context_data via _glapi_set{context,dispath_table} */ void* icd_save = IntGetCurrentICDPrivate(); const GLDISPATCHTABLE* table_save = IntGetCurrentDispatchTable(); /* Destroy everything */ _mesa_meta_free( &sw_ctx->mesa ); _swsetup_DestroyContext( &sw_ctx->mesa ); _tnl_DestroyContext( &sw_ctx->mesa ); _vbo_DestroyContext( &sw_ctx->mesa ); _swrast_DestroyContext( &sw_ctx->mesa ); _mesa_free_context_data( &sw_ctx->mesa ); free( sw_ctx ); /* Restore this */ IntSetCurrentDispatchTable(table_save); IntSetCurrentICDPrivate(icd_save); return TRUE; } PROC sw_GetProcAddress(LPCSTR name) { /* We don't support any extensions */ WARN("Asking for proc address %s, returning NULL.\n", name); return NULL; } BOOL sw_CopyContext(DHGLRC dhglrcSrc, DHGLRC dhglrcDst, UINT mask) { FIXME("Software wglCopyContext is UNIMPLEMENTED, mask %lx.\n", mask); return FALSE; } BOOL sw_ShareLists(DHGLRC dhglrcSrc, DHGLRC dhglrcDst) { struct sw_context* sw_ctx_src = (struct sw_context*)dhglrcSrc; struct sw_context* sw_ctx_dst = (struct sw_context*)dhglrcDst; /* See if it was already shared */ if(sw_ctx_dst->mesa.Shared->RefCount > 1) return FALSE; /* Unreference the old, share the new */ _mesa_reference_shared_state(&sw_ctx_dst->mesa, &sw_ctx_dst->mesa.Shared, sw_ctx_src->mesa.Shared); return TRUE; } static LRESULT CALLBACK sw_call_window_proc( int nCode, WPARAM wParam, LPARAM lParam ) { struct wgl_dc_data* dc_data = IntGetCurrentDcData(); struct sw_context* ctx = (struct sw_context*)IntGetCurrentDHGLRC(); struct sw_framebuffer* fb; PCWPSTRUCT pParams = (PCWPSTRUCT)lParam; if((!dc_data) || (!ctx)) return 0; if(!(dc_data->flags & WGL_DC_OBJ_DC)) return 0; if((nCode < 0) || (dc_data->owner.hwnd != pParams->hwnd) || (dc_data->sw_data == NULL)) return CallNextHookEx(ctx->hook, nCode, wParam, lParam); fb = dc_data->sw_data; if (pParams->message == WM_WINDOWPOSCHANGED) { /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it * can be masked out by the application. */ LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam; if((lpWindowPos->flags & SWP_SHOWWINDOW) || !(lpWindowPos->flags & SWP_NOMOVE) || !(lpWindowPos->flags & SWP_NOSIZE)) { /* Size in WINDOWPOS includes the window frame, so get the size * of the client area via GetClientRect. */ RECT client_rect; UINT width, height; TRACE("Got WM_WINDOWPOSCHANGED\n"); GetClientRect(pParams->hwnd, &client_rect); width = client_rect.right - client_rect.left; height = client_rect.bottom - client_rect.top; /* Do not reallocate for minimized windows */ if(width <= 0 || height <= 0) goto end; /* Update framebuffer size */ fb->bmi.bmiHeader.biWidth = width; fb->bmi.bmiHeader.biHeight = height; /* Propagate to mesa */ _mesa_resize_framebuffer(&ctx->mesa, fb->gl_buffer, width, height); } } end: return CallNextHookEx(ctx->hook, nCode, wParam, lParam); } BOOL sw_SetContext(struct wgl_dc_data* dc_data, DHGLRC dhglrc) { struct sw_context* sw_ctx = (struct sw_context*)dhglrc; struct sw_framebuffer* fb = dc_data->sw_data; UINT width, height; /* Update state */ sw_update_state(&sw_ctx->mesa, 0); /* Get framebuffer size */ if(dc_data->flags & WGL_DC_OBJ_DC) { HWND hwnd = dc_data->owner.hwnd; RECT client_rect; if(!hwnd) { ERR("Physical DC without a window!\n"); return FALSE; } if(!GetClientRect(hwnd, &client_rect)) { ERR("GetClientRect failed!\n"); return FALSE; } /* This is a physical DC. Setup the hook */ sw_ctx->hook = SetWindowsHookEx(WH_CALLWNDPROC, sw_call_window_proc, NULL, GetCurrentThreadId()); /* Calculate width & height */ width = client_rect.right - client_rect.left; height = client_rect.bottom - client_rect.top; } else /* OBJ_MEMDC */ { BITMAP bm; HBITMAP hbmp; HDC hdc = dc_data->owner.hdc; if(fb->flags & SW_FB_DOUBLEBUFFERED) { ERR("Memory DC called with a double buffered format.\n"); return FALSE; } hbmp = GetCurrentObject( hdc, OBJ_BITMAP ); if(!hbmp) { ERR("No Bitmap!\n"); return FALSE; } if(GetObject(hbmp, sizeof(bm), &bm) == 0) { ERR("GetObject failed!\n"); return FALSE; } width = bm.bmWidth; height = bm.bmHeight; } if(!width) width = 1; if(!height) height = 1; fb->bmi.bmiHeader.biWidth = width; fb->bmi.bmiHeader.biHeight = height; /* Also make the mesa context current to mesa */ if(!_mesa_make_current(&sw_ctx->mesa, fb->gl_buffer, fb->gl_buffer)) { ERR("_mesa_make_current filaed!\n"); return FALSE; } /* Set the viewport if this is the first time we initialize this context */ if(sw_ctx->mesa.Viewport.X == 0 && sw_ctx->mesa.Viewport.Y == 0 && sw_ctx->mesa.Viewport.Width == 0 && sw_ctx->mesa.Viewport.Height == 0) { _mesa_set_viewport(&sw_ctx->mesa, 0, 0, width, height); } /* update the framebuffer size */ _mesa_resize_framebuffer(&sw_ctx->mesa, fb->gl_buffer, width, height); /* We're good */ return TRUE; } void sw_ReleaseContext(DHGLRC dhglrc) { struct sw_context* sw_ctx = (struct sw_context*)dhglrc; /* Forward to mesa */ _mesa_make_current(NULL, NULL, NULL); /* Unhook */ if(sw_ctx->hook) { UnhookWindowsHookEx(sw_ctx->hook); sw_ctx->hook = NULL; } } BOOL sw_SwapBuffers(HDC hdc, struct wgl_dc_data* dc_data) { struct sw_framebuffer* fb = dc_data->sw_data; struct sw_context* sw_ctx = (struct sw_context*)IntGetCurrentDHGLRC(); /* Notify mesa */ if(sw_ctx) _mesa_notifySwapBuffers(&sw_ctx->mesa); if(!(fb->flags & SW_FB_DOUBLEBUFFERED)) return TRUE; /* Upload to the display */ return (SetDIBitsToDevice(hdc, 0, 0, fb->bmi.bmiHeader.biWidth, fb->bmi.bmiHeader.biHeight, 0, 0, 0, fb->bmi.bmiHeader.biHeight, fb->backbuffer.Buffer, &fb->bmi, DIB_RGB_COLORS) != 0); }