/* * Windows (Win32/Win64) device driver for Mesa * */ #include "wmesadef.h" #include "colors.h" #include "GL/wmesa.h" #include #include "main/context.h" #include "main/extensions.h" #include "main/framebuffer.h" #include "main/renderbuffer.h" #include "main/macros.h" #include "drivers/common/driverfuncs.h" #include "drivers/common/meta.h" #include "vbo/vbo.h" #include "swrast/swrast.h" #include "swrast/s_renderbuffer.h" #include "swrast_setup/swrast_setup.h" #include "tnl/tnl.h" #include "tnl/t_context.h" #include "tnl/t_pipeline.h" /* linked list of our Framebuffers (windows) */ static WMesaFramebuffer FirstFramebuffer = NULL; /** * Create a new WMesaFramebuffer object which will correspond to the * given HDC (Window handle). */ static WMesaFramebuffer wmesa_new_framebuffer(HDC hdc, struct gl_config *visual) { WMesaFramebuffer pwfb = (WMesaFramebuffer) malloc(sizeof(struct wmesa_framebuffer)); if (pwfb) { _mesa_initialize_window_framebuffer(&pwfb->Base, visual); pwfb->hDC = hdc; /* insert at head of list */ pwfb->next = FirstFramebuffer; FirstFramebuffer = pwfb; } return pwfb; } /** * Given an hdc, free the corresponding WMesaFramebuffer */ static void wmesa_free_framebuffer(HDC hdc) { WMesaFramebuffer pwfb, prev; for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) { if (pwfb->hDC == hdc) break; prev = pwfb; } if (pwfb) { struct gl_framebuffer *fb; if (pwfb == FirstFramebuffer) FirstFramebuffer = pwfb->next; else prev->next = pwfb->next; fb = &pwfb->Base; _mesa_reference_framebuffer(&fb, NULL); } } /** * Given an hdc, return the corresponding WMesaFramebuffer */ static WMesaFramebuffer wmesa_lookup_framebuffer(HDC hdc) { WMesaFramebuffer pwfb; for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) { if (pwfb->hDC == hdc) return pwfb; } return NULL; } /** * Given a struct gl_framebuffer, return the corresponding WMesaFramebuffer. */ static WMesaFramebuffer wmesa_framebuffer(struct gl_framebuffer *fb) { return (WMesaFramebuffer) fb; } /** * Given a struct gl_context, return the corresponding WMesaContext. */ static WMesaContext wmesa_context(const struct gl_context *ctx) { return (WMesaContext) ctx; } /* * Every driver should implement a GetString function in order to * return a meaningful GL_RENDERER string. */ static const GLubyte *wmesa_get_string(struct gl_context *ctx, GLenum name) { return (name == GL_RENDERER) ? (GLubyte *) "Mesa Windows GDI Driver" : NULL; } /* * Determine the pixel format based on the pixel size. */ static void wmSetPixelFormat(WMesaFramebuffer pwfb, HDC hDC) { pwfb->cColorBits = GetDeviceCaps(hDC, BITSPIXEL); /* Only 16 and 32 bit targets are supported now */ assert(pwfb->cColorBits == 0 || pwfb->cColorBits == 16 || pwfb->cColorBits == 24 || pwfb->cColorBits == 32); switch(pwfb->cColorBits){ case 8: pwfb->pixelformat = PF_INDEX8; break; case 16: pwfb->pixelformat = PF_5R6G5B; break; case 24: case 32: pwfb->pixelformat = PF_8R8G8B; break; default: pwfb->pixelformat = PF_BADFORMAT; } } /** * Create DIB for back buffer. * We write into this memory with the span routines and then blit it * to the window on a buffer swap. */ static BOOL wmCreateBackingStore(WMesaFramebuffer pwfb, long lxSize, long lySize) { LPBITMAPINFO pbmi = &(pwfb->bmi); HDC hic; pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pbmi->bmiHeader.biWidth = lxSize; pbmi->bmiHeader.biHeight= -lySize; pbmi->bmiHeader.biPlanes = 1; pbmi->bmiHeader.biBitCount = GetDeviceCaps(pwfb->hDC, BITSPIXEL); pbmi->bmiHeader.biCompression = BI_RGB; pbmi->bmiHeader.biSizeImage = 0; pbmi->bmiHeader.biXPelsPerMeter = 0; pbmi->bmiHeader.biYPelsPerMeter = 0; pbmi->bmiHeader.biClrUsed = 0; pbmi->bmiHeader.biClrImportant = 0; pwfb->cColorBits = pbmi->bmiHeader.biBitCount; pwfb->ScanWidth = (lxSize * (pwfb->cColorBits / 8) + 3) & ~3; hic = CreateIC("display", NULL, NULL, NULL); pwfb->dib_hDC = CreateCompatibleDC(hic); pwfb->hbmDIB = CreateDIBSection(hic, &pwfb->bmi, DIB_RGB_COLORS, (void **)&(pwfb->pbPixels), 0, 0); pwfb->hOldBitmap = SelectObject(pwfb->dib_hDC, pwfb->hbmDIB); DeleteDC(hic); wmSetPixelFormat(pwfb, pwfb->hDC); return TRUE; } static void wmDeleteBackingStore(WMesaFramebuffer pwfb) { if (pwfb->hbmDIB) { SelectObject(pwfb->dib_hDC, pwfb->hOldBitmap); DeleteDC(pwfb->dib_hDC); DeleteObject(pwfb->hbmDIB); } } /** * Find the width and height of the window named by hdc. */ static void get_window_size(HDC hdc, GLuint *width, GLuint *height) { if (WindowFromDC(hdc)) { RECT rect; GetClientRect(WindowFromDC(hdc), &rect); *width = rect.right - rect.left; *height = rect.bottom - rect.top; } else { /* Memory context */ /* From contributed code - use the size of the desktop * for the size of a memory context (?) */ *width = GetDeviceCaps(hdc, HORZRES); *height = GetDeviceCaps(hdc, VERTRES); } } static void wmesa_get_buffer_size(struct gl_framebuffer *buffer, GLuint *width, GLuint *height) { WMesaFramebuffer pwfb = wmesa_framebuffer(buffer); get_window_size(pwfb->hDC, width, height); } static void wmesa_flush(struct gl_context *ctx) { WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->WinSysDrawBuffer); if (ctx->Visual.doubleBufferMode == 1) { BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height, pwfb->dib_hDC, 0, 0, SRCCOPY); } else { /* Do nothing for single buffer */ } } /**********************************************************************/ /***** CLEAR Functions *****/ /**********************************************************************/ /* If we do not implement these, Mesa clears the buffers via the pixel * span writing interface, which is very slow for a clear operation. */ /* * Set the color used to clear the color buffer. */ static void clear_color(struct gl_context *ctx, const union gl_color_union color) { WMesaContext pwc = wmesa_context(ctx); GLubyte col[3]; UNCLAMPED_FLOAT_TO_UBYTE(col[0], color.f[0]); UNCLAMPED_FLOAT_TO_UBYTE(col[1], color.f[1]); UNCLAMPED_FLOAT_TO_UBYTE(col[2], color.f[2]); pwc->clearColorRef = RGB(col[0], col[1], col[2]); DeleteObject(pwc->clearPen); DeleteObject(pwc->clearBrush); pwc->clearPen = CreatePen(PS_SOLID, 1, pwc->clearColorRef); pwc->clearBrush = CreateSolidBrush(pwc->clearColorRef); } /* * Clear the specified region of the color buffer using the clear color * or index as specified by one of the two functions above. * * This procedure clears either the front and/or the back COLOR buffers. * Only the "left" buffer is cleared since we are not stereo. * Clearing of the other non-color buffers is left to the swrast. */ static void clear(struct gl_context *ctx, GLbitfield mask) { #define FLIP(Y) (ctx->DrawBuffer->Height - (Y) - 1) const GLint x = ctx->DrawBuffer->_Xmin; const GLint y = ctx->DrawBuffer->_Ymin; const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; WMesaContext pwc = wmesa_context(ctx); WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); int done = 0; /* Let swrast do all the work if the masks are not set to * clear all channels. */ if (!ctx->Color.ColorMask[0][0] || !ctx->Color.ColorMask[0][1] || !ctx->Color.ColorMask[0][2] || !ctx->Color.ColorMask[0][3]) { _swrast_Clear(ctx, mask); return; } /* Back buffer */ if (mask & BUFFER_BIT_BACK_LEFT) { int i, rowSize; UINT bytesPerPixel = pwfb->cColorBits / 8; LPBYTE lpb, clearRow; LPWORD lpw; BYTE bColor; WORD wColor; BYTE r, g, b; DWORD dwColor; LPDWORD lpdw; /* Try for a fast clear - clearing entire buffer with a single * byte value. */ if (width == ctx->DrawBuffer->Width && height == ctx->DrawBuffer->Height) { /* entire buffer */ /* Now check for an easy clear value */ switch (bytesPerPixel) { case 1: bColor = BGR8(GetRValue(pwc->clearColorRef), GetGValue(pwc->clearColorRef), GetBValue(pwc->clearColorRef)); memset(pwfb->pbPixels, bColor, pwfb->ScanWidth * height); done = 1; break; case 2: wColor = BGR16(GetRValue(pwc->clearColorRef), GetGValue(pwc->clearColorRef), GetBValue(pwc->clearColorRef)); if (((wColor >> 8) & 0xff) == (wColor & 0xff)) { memset(pwfb->pbPixels, wColor & 0xff, pwfb->ScanWidth * height); done = 1; } break; case 3: /* fall through */ case 4: if (GetRValue(pwc->clearColorRef) == GetGValue(pwc->clearColorRef) && GetRValue(pwc->clearColorRef) == GetBValue(pwc->clearColorRef)) { memset(pwfb->pbPixels, GetRValue(pwc->clearColorRef), pwfb->ScanWidth * height); done = 1; } break; default: break; } } /* all */ if (!done) { /* Need to clear a row at a time. Begin by setting the first * row in the area to be cleared to the clear color. */ clearRow = pwfb->pbPixels + pwfb->ScanWidth * FLIP(y) + bytesPerPixel * x; switch (bytesPerPixel) { case 1: lpb = clearRow; bColor = BGR8(GetRValue(pwc->clearColorRef), GetGValue(pwc->clearColorRef), GetBValue(pwc->clearColorRef)); memset(lpb, bColor, width); break; case 2: lpw = (LPWORD)clearRow; wColor = BGR16(GetRValue(pwc->clearColorRef), GetGValue(pwc->clearColorRef), GetBValue(pwc->clearColorRef)); for (i=0; iclearColorRef); g = GetGValue(pwc->clearColorRef); b = GetBValue(pwc->clearColorRef); for (i=0; iclearColorRef), GetGValue(pwc->clearColorRef), GetBValue(pwc->clearColorRef)); for (i=0; iScanWidth; rowSize = width * bytesPerPixel; for (i=1; iScanWidth; } } /* not done */ mask &= ~BUFFER_BIT_BACK_LEFT; } /* back buffer */ /* front buffer */ if (mask & BUFFER_BIT_FRONT_LEFT) { HDC DC = pwc->hDC; HPEN Old_Pen = SelectObject(DC, pwc->clearPen); HBRUSH Old_Brush = SelectObject(DC, pwc->clearBrush); Rectangle(DC, x, FLIP(y) + 1, x + width + 1, FLIP(y) - height + 1); SelectObject(DC, Old_Pen); SelectObject(DC, Old_Brush); mask &= ~BUFFER_BIT_FRONT_LEFT; } /* front buffer */ /* Call swrast if there is anything left to clear (like DEPTH) */ if (mask) _swrast_Clear(ctx, mask); #undef FLIP } /**********************************************************************/ /***** PIXEL Functions *****/ /**********************************************************************/ #define FLIP(Y) (rb->Height - (Y) - 1) /** ** Front Buffer reading/writing ** These are slow, but work with all non-indexed visual types. **/ /* Write a horizontal span of RGBA color pixels with a boolean mask. */ static void write_rgba_span_front(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, GLint x, GLint y, const void *values, const GLubyte *mask) { const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values; WMesaContext pwc = wmesa_context(ctx); WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(pwc->hDC); HBITMAP bmp=0; HDC mdc=0; typedef union { unsigned i; struct { unsigned b:8, g:8, r:8, a:8; }; } BGRA; BGRA *bgra, c; GLuint i; if (n < 16) { // the value 16 is just guessed y=FLIP(y); if (mask) { for (i=0; ihDC, x+i, y, RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP])); } else { for (i=0; ihDC, x+i, y, RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP])); } } else { if (!pwfb) { _mesa_problem(NULL, "wmesa: write_rgba_span_front on unknown hdc"); return; } bgra=malloc(n*sizeof(BGRA)); if (!bgra) { _mesa_problem(NULL, "wmesa: write_rgba_span_front: out of memory"); return; } c.a=0; if (mask) { for (i=0; ihDC); SelectObject(mdc, bmp); y=FLIP(y); BitBlt(pwfb->hDC, x, y, n, 1, mdc, 0, 0, SRCCOPY); SelectObject(mdc, 0); DeleteObject(bmp); DeleteDC(mdc); free(bgra); } } /* Write a horizontal span of RGB color pixels with a boolean mask. */ static void write_rgb_span_front(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, GLint x, GLint y, const void *values, const GLubyte *mask) { const GLubyte (*rgb)[3] = (const GLubyte (*)[3])values; WMesaContext pwc = wmesa_context(ctx); GLuint i; (void) ctx; y=FLIP(y); if (mask) { for (i=0; ihDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP], rgb[i][BCOMP])); } else { for (i=0; ihDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP], rgb[i][BCOMP])); } } /* Write an array of RGBA pixels with a boolean mask. */ static void write_rgba_pixels_front(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, const GLint x[], const GLint y[], const void *values, const GLubyte *mask) { const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values; GLuint i; WMesaContext pwc = wmesa_context(ctx); (void) ctx; for (i=0; ihDC, x[i], FLIP(y[i]), RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP])); } /* Read a horizontal span of color pixels. */ static void read_rgba_span_front(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, GLint x, GLint y, void *values) { GLubyte (*rgba)[4] = (GLubyte (*)[4])values; WMesaContext pwc = wmesa_context(ctx); GLuint i; COLORREF Color; y = FLIP(y); for (i=0; ihDC, x+i, y); rgba[i][RCOMP] = GetRValue(Color); rgba[i][GCOMP] = GetGValue(Color); rgba[i][BCOMP] = GetBValue(Color); rgba[i][ACOMP] = 255; } } /* Read an array of color pixels. */ static void read_rgba_pixels_front(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, const GLint x[], const GLint y[], void *values) { GLubyte (*rgba)[4] = (GLubyte (*)[4])values; WMesaContext pwc = wmesa_context(ctx); GLuint i; COLORREF Color; for (i=0; ihDC, x[i], y2); rgba[i][RCOMP] = GetRValue(Color); rgba[i][GCOMP] = GetGValue(Color); rgba[i][BCOMP] = GetBValue(Color); rgba[i][ACOMP] = 255; } } /*********************************************************************/ /* DOUBLE BUFFER 32-bit */ #define WMSETPIXEL32(pwc, y, x, r, g, b) { \ LPDWORD lpdw = ((LPDWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \ *lpdw = BGR32((r),(g),(b)); } /* Write a horizontal span of RGBA color pixels with a boolean mask. */ static void write_rgba_span_32(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, GLint x, GLint y, const void *values, const GLubyte *mask) { const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values; WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); GLuint i; LPDWORD lpdw; (void) ctx; y=FLIP(y); lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; if (mask) { for (i=0; iDrawBuffer); GLuint i; LPDWORD lpdw; (void) ctx; y=FLIP(y); lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; if (mask) { for (i=0; iDrawBuffer); for (i=0; iDrawBuffer); y = FLIP(y); lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; for (i=0; i> 16); rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8); rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff); rgba[i][ACOMP] = 255; } } /* Read an array of color pixels. */ static void read_rgba_pixels_32(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, const GLint x[], const GLint y[], void *values) { GLubyte (*rgba)[4] = (GLubyte (*)[4])values; GLuint i; DWORD pixel; LPDWORD lpdw; WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); for (i=0; ipbPixels + pwfb->ScanWidth * y2)) + x[i]; pixel = *lpdw; rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 16); rgba[i][GCOMP] = (GLubyte)((pixel & 0x0000ff00) >> 8); rgba[i][BCOMP] = (GLubyte)(pixel & 0x000000ff); rgba[i][ACOMP] = 255; } } /*********************************************************************/ /* DOUBLE BUFFER 24-bit */ #define WMSETPIXEL24(pwc, y, x, r, g, b) { \ LPBYTE lpb = ((LPBYTE)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (3 * x)); \ lpb[0] = (b); \ lpb[1] = (g); \ lpb[2] = (r); } /* Write a horizontal span of RGBA color pixels with a boolean mask. */ static void write_rgba_span_24(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, GLint x, GLint y, const void *values, const GLubyte *mask) { const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values; WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); GLuint i; LPBYTE lpb; (void) ctx; y=FLIP(y); lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); if (mask) { for (i=0; iDrawBuffer); GLuint i; LPBYTE lpb; (void) ctx; y=FLIP(y); lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); if (mask) { for (i=0; iDrawBuffer); for (i=0; iDrawBuffer); y = FLIP(y); lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); for (i=0; iDrawBuffer); for (i=0; ipbPixels + pwfb->ScanWidth * y2)) + (3 * x[i]); rgba[i][RCOMP] = lpb[3*i+2]; rgba[i][GCOMP] = lpb[3*i+1]; rgba[i][BCOMP] = lpb[3*i]; rgba[i][ACOMP] = 255; } } /*********************************************************************/ /* DOUBLE BUFFER 16-bit */ #define WMSETPIXEL16(pwc, y, x, r, g, b) { \ LPWORD lpw = ((LPWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \ *lpw = BGR16((r),(g),(b)); } /* Write a horizontal span of RGBA color pixels with a boolean mask. */ static void write_rgba_span_16(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, GLint x, GLint y, const void *values, const GLubyte *mask) { const GLubyte (*rgba)[4] = (const GLubyte (*)[4])values; WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); GLuint i; LPWORD lpw; (void) ctx; y=FLIP(y); lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; if (mask) { for (i=0; iDrawBuffer); GLuint i; LPWORD lpw; (void) ctx; y=FLIP(y); lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; if (mask) { for (i=0; iDrawBuffer); (void) ctx; for (i=0; iDrawBuffer); y = FLIP(y); lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; for (i=0; i> 7; rgba[i][GCOMP] = (pixel & 0x03e0) >> 2; rgba[i][BCOMP] = (pixel & 0x001f) << 3; rgba[i][ACOMP] = 255; } } /* Read an array of color pixels. */ static void read_rgba_pixels_16(struct gl_context *ctx, struct gl_renderbuffer *rb, GLuint n, const GLint x[], const GLint y[], void *values) { GLubyte (*rgba)[4] = (GLubyte (*)[4])values; GLuint i, pixel; LPWORD lpw; WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); for (i=0; ipbPixels + pwfb->ScanWidth * y2)) + x[i]; pixel = *lpw; /* Windows uses 5,5,5 for 16-bit */ rgba[i][RCOMP] = (pixel & 0x7c00) >> 7; rgba[i][GCOMP] = (pixel & 0x03e0) >> 2; rgba[i][BCOMP] = (pixel & 0x001f) << 3; rgba[i][ACOMP] = 255; } } /**********************************************************************/ /***** BUFFER Functions *****/ /**********************************************************************/ static void wmesa_delete_renderbuffer(struct gl_renderbuffer *rb) { free(rb); } /** * This is called by Mesa whenever it determines that the window size * has changed. Do whatever's needed to cope with that. */ static GLboolean wmesa_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, GLenum internalFormat, GLuint width, GLuint height) { rb->Width = width; rb->Height = height; return GL_TRUE; } /** * Plug in the Get/PutRow/Values functions for a renderbuffer depending * on if we're drawing to the front or back color buffer. */ static void wmesa_set_renderbuffer_funcs(struct gl_renderbuffer *rb, int pixelformat, int cColorBits, int double_buffer) { if (double_buffer) { /* back buffer */ /* Picking the correct span functions is important because * the DIB was allocated with the indicated depth. */ switch(pixelformat) { case PF_5R6G5B: rb->PutRow = write_rgba_span_16; rb->PutRowRGB = write_rgb_span_16; rb->PutValues = write_rgba_pixels_16; rb->GetRow = read_rgba_span_16; rb->GetValues = read_rgba_pixels_16; break; case PF_8R8G8B: if (cColorBits == 24) { rb->PutRow = write_rgba_span_24; rb->PutRowRGB = write_rgb_span_24; rb->PutValues = write_rgba_pixels_24; rb->GetRow = read_rgba_span_24; rb->GetValues = read_rgba_pixels_24; } else { rb->PutRow = write_rgba_span_32; rb->PutRowRGB = write_rgb_span_32; rb->PutValues = write_rgba_pixels_32; rb->GetRow = read_rgba_span_32; rb->GetValues = read_rgba_pixels_32; } break; default: break; } } else { /* front buffer (actual Windows window) */ rb->PutRow = write_rgba_span_front; rb->PutRowRGB = write_rgb_span_front; rb->PutValues = write_rgba_pixels_front; rb->GetRow = read_rgba_span_front; rb->GetValues = read_rgba_pixels_front; } } /** * Called by ctx->Driver.ResizeBuffers() * Resize the front/back colorbuffers to match the latest window size. */ static void wmesa_resize_buffers(struct gl_context *ctx, struct gl_framebuffer *buffer, GLuint width, GLuint height) { WMesaFramebuffer pwfb = wmesa_framebuffer(buffer); if (pwfb->Base.Width != width || pwfb->Base.Height != height) { /* Realloc back buffer */ if (ctx->Visual.doubleBufferMode == 1) { wmDeleteBackingStore(pwfb); wmCreateBackingStore(pwfb, width, height); } } _mesa_resize_framebuffer(ctx, buffer, width, height); } /** * Called by glViewport. * This is a good time for us to poll the current window size and adjust * our renderbuffers to match the current window size. * Remember, we have no opportunity to respond to conventional * resize events since the driver has no event loop. * Thus, we poll. * MakeCurrent also ends up making a call here, so that ensures * we get the viewport set correctly, even if the app does not call * glViewport and relies on the defaults. */ static void wmesa_viewport(struct gl_context *ctx, GLint x, GLint y, GLsizei width, GLsizei height) { GLuint new_width, new_height; wmesa_get_buffer_size(ctx->WinSysDrawBuffer, &new_width, &new_height); /** * Resize buffers if the window size changed. */ wmesa_resize_buffers(ctx, ctx->WinSysDrawBuffer, new_width, new_height); ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */ } /** * Called when the driver should update it's state, based on the new_state * flags. */ static void wmesa_update_state(struct gl_context *ctx, GLuint new_state) { _swrast_InvalidateState(ctx, new_state); _swsetup_InvalidateState(ctx, new_state); _vbo_InvalidateState(ctx, new_state); _tnl_InvalidateState(ctx, new_state); /* TODO - This code is not complete yet because I * don't know what to do for all state updates. */ if (new_state & _NEW_BUFFERS) { } } /**********************************************************************/ /***** WMESA Functions *****/ /**********************************************************************/ WMesaContext WMesaCreateContext(HDC hDC, HPALETTE* Pal, GLboolean rgb_flag, GLboolean db_flag, GLboolean alpha_flag) { WMesaContext c; struct dd_function_table functions; GLint red_bits, green_bits, blue_bits, alpha_bits; struct gl_context *ctx; struct gl_config *visual; (void) Pal; /* Indexed mode not supported */ if (!rgb_flag) return NULL; /* Allocate wmesa context */ c = CALLOC_STRUCT(wmesa_context); if (!c) return NULL; #if 0 /* I do not understand this contributed code */ /* Support memory and device contexts */ if(WindowFromDC(hDC) != NULL) { c->hDC = GetDC(WindowFromDC(hDC)); /* huh ???? */ } else { c->hDC = hDC; } #else c->hDC = hDC; #endif /* Get data for visual */ /* Dealing with this is actually a bit of overkill because Mesa will end * up treating all color component size requests less than 8 by using * a single byte per channel. In addition, the interface to the span * routines passes colors as an entire byte per channel anyway, so there * is nothing to be saved by telling the visual to be 16 bits if the device * is 16 bits. That is, Mesa is going to compute colors down to 8 bits per * channel anyway. * But we go through the motions here anyway. */ switch (GetDeviceCaps(c->hDC, BITSPIXEL)) { case 16: red_bits = green_bits = blue_bits = 5; alpha_bits = 0; break; default: red_bits = green_bits = blue_bits = 8; alpha_bits = 8; break; } /* Create visual based on flags */ visual = _mesa_create_visual(db_flag, /* db_flag */ GL_FALSE, /* stereo */ red_bits, green_bits, blue_bits, /* color RGB */ alpha_flag ? alpha_bits : 0, /* color A */ DEFAULT_SOFTWARE_DEPTH_BITS, /* depth_bits */ 8, /* stencil_bits */ 16,16,16, /* accum RGB */ alpha_flag ? 16 : 0, /* accum A */ 1); /* num samples */ if (!visual) { free(c); return NULL; } /* Set up driver functions */ _mesa_init_driver_functions(&functions); functions.GetString = wmesa_get_string; functions.UpdateState = wmesa_update_state; functions.GetBufferSize = wmesa_get_buffer_size; functions.Flush = wmesa_flush; functions.Clear = clear; functions.ClearColor = clear_color; functions.ResizeBuffers = wmesa_resize_buffers; functions.Viewport = wmesa_viewport; /* initialize the Mesa context data */ ctx = &c->gl_ctx; _mesa_initialize_context(ctx, API_OPENGL, visual, NULL, &functions, (void *)c); /* visual no longer needed - it was copied by _mesa_initialize_context() */ _mesa_destroy_visual(visual); _mesa_enable_sw_extensions(ctx); _mesa_enable_1_3_extensions(ctx); _mesa_enable_1_4_extensions(ctx); _mesa_enable_1_5_extensions(ctx); _mesa_enable_2_0_extensions(ctx); _mesa_enable_2_1_extensions(ctx); _mesa_meta_init(ctx); /* Initialize the software rasterizer and helper modules. */ if (!_swrast_CreateContext(ctx) || !_vbo_CreateContext(ctx) || !_tnl_CreateContext(ctx) || !_swsetup_CreateContext(ctx)) { _mesa_free_context_data(ctx); free(c); return NULL; } _swsetup_Wakeup(ctx); TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline; return c; } void WMesaDestroyContext( WMesaContext pwc ) { struct gl_context *ctx = &pwc->gl_ctx; WMesaFramebuffer pwfb; GET_CURRENT_CONTEXT(cur_ctx); if (cur_ctx == ctx) { /* unbind current if deleting current context */ WMesaMakeCurrent(NULL, NULL); } /* clean up frame buffer resources */ pwfb = wmesa_lookup_framebuffer(pwc->hDC); if (pwfb) { if (ctx->Visual.doubleBufferMode == 1) wmDeleteBackingStore(pwfb); wmesa_free_framebuffer(pwc->hDC); } /* Release for device, not memory contexts */ if (WindowFromDC(pwc->hDC) != NULL) { ReleaseDC(WindowFromDC(pwc->hDC), pwc->hDC); } DeleteObject(pwc->clearPen); DeleteObject(pwc->clearBrush); _mesa_meta_free(ctx); _swsetup_DestroyContext(ctx); _tnl_DestroyContext(ctx); _vbo_DestroyContext(ctx); _swrast_DestroyContext(ctx); _mesa_free_context_data(ctx); free(pwc); } /** * Create a new color renderbuffer. */ static struct gl_renderbuffer * wmesa_new_renderbuffer(void) { struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer); if (!rb) return NULL; _mesa_init_renderbuffer(rb, (GLuint)0); rb->_BaseFormat = GL_RGBA; rb->InternalFormat = GL_RGBA; rb->DataType = CHAN_TYPE; rb->Delete = wmesa_delete_renderbuffer; rb->AllocStorage = wmesa_renderbuffer_storage; return rb; } void WMesaMakeCurrent(WMesaContext c, HDC hdc) { WMesaFramebuffer pwfb; { /* return if already current */ GET_CURRENT_CONTEXT(ctx); WMesaContext pwc = wmesa_context(ctx); if (pwc && c == pwc && pwc->hDC == hdc) return; } pwfb = wmesa_lookup_framebuffer(hdc); /* Lazy creation of framebuffers */ if (c && !pwfb && hdc) { struct gl_renderbuffer *rb; struct gl_config *visual = &c->gl_ctx.Visual; GLuint width, height; get_window_size(hdc, &width, &height); c->clearPen = CreatePen(PS_SOLID, 1, 0); c->clearBrush = CreateSolidBrush(0); pwfb = wmesa_new_framebuffer(hdc, visual); /* Create back buffer if double buffered */ if (visual->doubleBufferMode == 1) { wmCreateBackingStore(pwfb, width, height); } /* make render buffers */ if (visual->doubleBufferMode == 1) { rb = wmesa_new_renderbuffer(); _mesa_add_renderbuffer(&pwfb->Base, BUFFER_BACK_LEFT, rb); wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 1); } rb = wmesa_new_renderbuffer(); _mesa_add_renderbuffer(&pwfb->Base, BUFFER_FRONT_LEFT, rb); wmesa_set_renderbuffer_funcs(rb, pwfb->pixelformat, pwfb->cColorBits, 0); /* Let Mesa own the Depth, Stencil, and Accum buffers */ _swrast_add_soft_renderbuffers(&pwfb->Base, GL_FALSE, /* color */ visual->depthBits > 0, visual->stencilBits > 0, visual->accumRedBits > 0, visual->alphaBits >0, GL_FALSE); } if (c && pwfb) _mesa_make_current(&c->gl_ctx, &pwfb->Base, &pwfb->Base); else _mesa_make_current(NULL, NULL, NULL); } void WMesaSwapBuffers( HDC hdc ) { GET_CURRENT_CONTEXT(ctx); WMesaContext pwc = wmesa_context(ctx); WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(hdc); if (!pwfb) { _mesa_problem(NULL, "wmesa: swapbuffers on unknown hdc"); return; } /* If we're swapping the buffer associated with the current context * we have to flush any pending rendering commands first. */ if (pwc->hDC == hdc) { _mesa_notifySwapBuffers(ctx); BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height, pwfb->dib_hDC, 0, 0, SRCCOPY); } else { /* XXX for now only allow swapping current window */ _mesa_problem(NULL, "wmesa: can't swap non-current window"); } } void WMesaShareLists(WMesaContext ctx_to_share, WMesaContext ctx) { _mesa_share_state(&ctx->gl_ctx, &ctx_to_share->gl_ctx); }