| /* |
| * Windows (Win32/Win64) device driver for Mesa |
| * |
| */ |
| |
| #include "wmesadef.h" |
| #include "colors.h" |
| #include "GL/wmesa.h" |
| #include <winuser.h> |
| #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 *****/ |
| /**********************************************************************/ |
| |
| /* |
| * Clear the color/depth/stencil buffers. |
| */ |
| 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; |
| } |
| |
| if (mask & BUFFER_BITS_COLOR) { |
| /* setup the clearing color */ |
| const union gl_color_union color = ctx->Color.ClearColor; |
| 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); |
| } |
| |
| /* 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; i<width; i++) |
| *lpw++ = wColor; |
| break; |
| case 3: |
| lpb = clearRow; |
| r = GetRValue(pwc->clearColorRef); |
| g = GetGValue(pwc->clearColorRef); |
| b = GetBValue(pwc->clearColorRef); |
| for (i=0; i<width; i++) { |
| *lpb++ = b; |
| *lpb++ = g; |
| *lpb++ = r; |
| } |
| break; |
| case 4: |
| lpdw = (LPDWORD)clearRow; |
| dwColor = BGR32(GetRValue(pwc->clearColorRef), |
| GetGValue(pwc->clearColorRef), |
| GetBValue(pwc->clearColorRef)); |
| for (i=0; i<width; i++) |
| *lpdw++ = dwColor; |
| break; |
| default: |
| break; |
| } /* switch */ |
| |
| /* copy cleared row to other rows in buffer */ |
| lpb = clearRow - pwfb->ScanWidth; |
| rowSize = width * bytesPerPixel; |
| for (i=1; i<height; i++) { |
| memcpy(lpb, clearRow, rowSize); |
| lpb -= pwfb->ScanWidth; |
| } |
| } /* 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; i<n; i++) |
| if (mask[i]) |
| SetPixel(pwc->hDC, x+i, y, |
| RGB(rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP])); |
| } |
| else { |
| for (i=0; i<n; i++) |
| SetPixel(pwc->hDC, 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; i<n; i++) { |
| if (mask[i]) { |
| c.r=rgba[i][RCOMP]; |
| c.g=rgba[i][GCOMP]; |
| c.b=rgba[i][BCOMP]; |
| c.a=rgba[i][ACOMP]; |
| bgra[i]=c; |
| } |
| else |
| bgra[i].i=0; |
| } |
| } |
| else { |
| for (i=0; i<n; i++) { |
| c.r=rgba[i][RCOMP]; |
| c.g=rgba[i][GCOMP]; |
| c.b=rgba[i][BCOMP]; |
| c.a=rgba[i][ACOMP]; |
| bgra[i]=c; |
| } |
| } |
| bmp=CreateBitmap(n, 1, 1, 32, bgra); |
| mdc=CreateCompatibleDC(pwfb->hDC); |
| 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 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; i<n; i++) |
| if (mask[i]) |
| SetPixel(pwc->hDC, 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; i<n; i++) { |
| Color = GetPixel(pwc->hDC, 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; i<n; i++) { |
| GLint y2 = FLIP(y[i]); |
| Color = GetPixel(pwc->hDC, 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; i<n; i++) |
| if (mask[i]) |
| lpdw[i] = BGR32(rgba[i][RCOMP], rgba[i][GCOMP], |
| rgba[i][BCOMP]); |
| } |
| else { |
| for (i=0; i<n; i++) |
| *lpdw++ = BGR32(rgba[i][RCOMP], rgba[i][GCOMP], |
| rgba[i][BCOMP]); |
| } |
| } |
| |
| |
| /* Write an array of RGBA pixels with a boolean mask. */ |
| static void write_rgba_pixels_32(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; |
| WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); |
| for (i=0; i<n; i++) |
| if (mask[i]) |
| WMSETPIXEL32(pwfb, FLIP(y[i]), x[i], |
| rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); |
| } |
| |
| |
| /* Read a horizontal span of color pixels. */ |
| static void read_rgba_span_32(struct gl_context *ctx, |
| struct gl_renderbuffer *rb, |
| GLuint n, GLint x, GLint y, |
| void *values) |
| { |
| GLubyte (*rgba)[4] = (GLubyte (*)[4])values; |
| GLuint i; |
| DWORD pixel; |
| LPDWORD lpdw; |
| WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); |
| |
| y = FLIP(y); |
| lpdw = ((LPDWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; |
| for (i=0; i<n; i++) { |
| pixel = lpdw[i]; |
| rgba[i][RCOMP] = (GLubyte)((pixel & 0x00ff0000) >> 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; i<n; i++) { |
| GLint y2 = FLIP(y[i]); |
| lpdw = ((LPDWORD)(pwfb->pbPixels + 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; i<n; i++) |
| if (mask[i]) { |
| lpb[3*i] = rgba[i][BCOMP]; |
| lpb[3*i+1] = rgba[i][GCOMP]; |
| lpb[3*i+2] = rgba[i][RCOMP]; |
| } |
| } |
| else { |
| for (i=0; i<n; i++) { |
| *lpb++ = rgba[i][BCOMP]; |
| *lpb++ = rgba[i][GCOMP]; |
| *lpb++ = rgba[i][RCOMP]; |
| } |
| } |
| } |
| |
| |
| /* Write an array of RGBA pixels with a boolean mask. */ |
| static void write_rgba_pixels_24(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; |
| WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); |
| for (i=0; i<n; i++) |
| if (mask[i]) |
| WMSETPIXEL24(pwfb, FLIP(y[i]), x[i], |
| rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); |
| } |
| |
| |
| /* Read a horizontal span of color pixels. */ |
| static void read_rgba_span_24(struct gl_context *ctx, |
| struct gl_renderbuffer *rb, |
| GLuint n, GLint x, GLint y, |
| void *values) |
| { |
| GLubyte (*rgba)[4] = (GLubyte (*)[4])values; |
| GLuint i; |
| LPBYTE lpb; |
| WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); |
| |
| y = FLIP(y); |
| lpb = ((LPBYTE)(pwfb->pbPixels + pwfb->ScanWidth * y)) + (3 * x); |
| for (i=0; i<n; 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; |
| } |
| } |
| |
| |
| /* Read an array of color pixels. */ |
| static void read_rgba_pixels_24(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; |
| LPBYTE lpb; |
| WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); |
| |
| for (i=0; i<n; i++) { |
| GLint y2 = FLIP(y[i]); |
| lpb = ((LPBYTE)(pwfb->pbPixels + 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; i<n; i++) |
| if (mask[i]) |
| lpw[i] = BGR16(rgba[i][RCOMP], rgba[i][GCOMP], |
| rgba[i][BCOMP]); |
| } |
| else { |
| for (i=0; i<n; i++) |
| *lpw++ = BGR16(rgba[i][RCOMP], rgba[i][GCOMP], |
| rgba[i][BCOMP]); |
| } |
| } |
| |
| |
| |
| /* Write an array of RGBA pixels with a boolean mask. */ |
| static void write_rgba_pixels_16(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; |
| WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); |
| (void) ctx; |
| for (i=0; i<n; i++) |
| if (mask[i]) |
| WMSETPIXEL16(pwfb, FLIP(y[i]), x[i], |
| rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); |
| } |
| |
| |
| /* Read a horizontal span of color pixels. */ |
| static void read_rgba_span_16(struct gl_context *ctx, |
| struct gl_renderbuffer *rb, |
| GLuint n, GLint x, GLint y, |
| void *values) |
| { |
| GLubyte (*rgba)[4] = (GLubyte (*)[4])values; |
| GLuint i, pixel; |
| LPWORD lpw; |
| WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer); |
| |
| y = FLIP(y); |
| lpw = ((LPWORD)(pwfb->pbPixels + pwfb->ScanWidth * y)) + x; |
| for (i=0; i<n; i++) { |
| pixel = lpw[i]; |
| /* 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; |
| } |
| } |
| |
| |
| /* 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; i<n; i++) { |
| GLint y2 = FLIP(y[i]); |
| lpw = ((LPWORD)(pwfb->pbPixels + 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_context *ctx, struct gl_renderbuffer *rb) |
| { |
| _mesa_delete_renderbuffer(ctx, 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; |
| } |
| |
| |
| /** |
| * 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.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->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); |
| } |
| rb = wmesa_new_renderbuffer(); |
| _mesa_add_renderbuffer(&pwfb->Base, BUFFER_FRONT_LEFT, rb); |
| |
| /* 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); |
| } |
| |