Author: jgardou
Date: Tue Sep 17 23:24:13 2013
New Revision: 60197
URL:
http://svn.reactos.org/svn/reactos?rev=60197&view=rev
Log:
[OPENGL32_NEW]
- Implement reading from the frontbuffer.
Modified:
trunk/reactos/dll/opengl/opengl32_new/swimpl.c
Modified: trunk/reactos/dll/opengl/opengl32_new/swimpl.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/opengl/opengl32_new/sw…
==============================================================================
--- trunk/reactos/dll/opengl/opengl32_new/swimpl.c [iso-8859-1] (original)
+++ trunk/reactos/dll/opengl/opengl32_new/swimpl.c [iso-8859-1] Tue Sep 17 23:24:13 2013
@@ -12,6 +12,8 @@
#include <wine/debug.h>
WINE_DEFAULT_DEBUG_CHANNEL(opengl32);
+
+#define WIDTH_BYTES_ALIGN32(cx, bpp) ((((cx) * (bpp) + 31) & ~31) >> 3)
/* OSMesa stuff */
static HMODULE hMesaDll = NULL;
@@ -28,26 +30,45 @@
OSMesaContext mesa_ctx;
HHOOK hook;
struct sw_framebuffer* framebuffer;
+ GLenum readmode;
};
#define SW_FB_DOUBLEBUFFERED 0x1
#define SW_FB_DIBSECTION 0x2
#define SW_FB_FREE_BITS 0x4
+#define SW_FB_DIRTY_BITS 0x8
+#define SW_FB_DIRTY_SIZE 0x10
+#define SW_FB_DIRTY (SW_FB_DIRTY_BITS | SW_FB_DIRTY_SIZE)
+
struct sw_framebuffer
{
INT sw_format;
UINT format_index;
- void* bits;
+ union
+ {
+ void* backbuffer;
+ void* bits;
+ };
+ void* frontbuffer;
DWORD flags;
BITMAPINFO bmi;
};
-/* For our special SB glFinish implementation */
+/*
+ * Functions that we shadow to compensate with the impossibility
+ * to use double buffered format in osmesa
+ */
static void (GLAPIENTRY * pFinish)(void);
-
-/* Single buffered API table */
+static void (GLAPIENTRY * pReadBuffer)(GLenum);
+static void (GLAPIENTRY * pGetBooleanv)(GLenum pname, GLboolean* params);
+static void (GLAPIENTRY * pGetFloatv)(GLenum pname, GLfloat* params);
+static void (GLAPIENTRY * pGetDoublev)(GLenum pname, GLdouble* params);
+static void (GLAPIENTRY * pGetIntegerv)(GLenum pname, GLint* params);
+static void (GLAPIENTRY * pReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height,
GLenum format, GLenum type, GLvoid *pixels);
+
+/* API table for single buffered mode */
static GLCLTPROCTABLE sw_table_sb;
-/* Double buffered API table */
+/* API table for double buffered mode */
static GLCLTPROCTABLE sw_table_db;
static const struct
@@ -77,12 +98,12 @@
{ OSMESA_RGB_565, 16, 5, 0, 6, 5, 5, 11, 0, 0, 16, 16, 8 },
};
-/* glFinish for single-buffered pixel formats */
+/* Single buffered format specifics */
static void GLAPIENTRY sw_sb_Finish(void)
{
struct wgl_dc_data* dc_data = IntGetCurrentDcData();
struct sw_framebuffer* fb;
- HDC hdc;
+ HDC hdc = IntGetCurrentDC();
/* Call osmesa */
pFinish();
@@ -91,13 +112,9 @@
fb = dc_data->sw_data;
assert(fb != NULL);
+ /* osmesa directly updated the bits of the DIB section */
if(fb->flags & SW_FB_DIBSECTION)
return;
-
- if(dc_data->flags & WGL_DC_OBJ_DC)
- hdc = GetDC(dc_data->owner.hwnd);
- else
- hdc = dc_data->owner.hdc;
/* Upload the data to the device */
SetDIBitsToDevice(hdc,
@@ -112,11 +129,178 @@
fb->bits,
&fb->bmi,
DIB_RGB_COLORS);
-
- if(dc_data->flags & WGL_DC_OBJ_DC)
- ReleaseDC(dc_data->owner.hwnd, hdc);
-}
-
+}
+
+/* Double buffered format specifics */
+static void sw_db_update_frontbuffer(struct sw_framebuffer* fb, HDC hdc)
+{
+ unsigned int widthbytes = WIDTH_BYTES_ALIGN32(fb->bmi.bmiHeader.biWidth,
+ pixel_formats[fb->format_index].color_bits);
+ size_t buffer_size = widthbytes*fb->bmi.bmiHeader.biHeight;
+ if(fb->flags & SW_FB_DIRTY_SIZE)
+ {
+ if(fb->frontbuffer)
+ fb->frontbuffer = HeapReAlloc(GetProcessHeap(), 0, fb->frontbuffer,
buffer_size);
+ else
+ fb->frontbuffer = HeapAlloc(GetProcessHeap(), 0, buffer_size);
+ fb->flags ^= SW_FB_DIRTY_SIZE;
+ }
+
+ if(fb->flags & SW_FB_DIRTY_BITS)
+ {
+ /* On windows, there is SetDIBitsToDevice, but not FROM device... */
+ HBITMAP hbmp;
+ HDC hmemDC = CreateCompatibleDC(hdc);
+ void* DIBits;
+ hbmp = CreateDIBSection(hdc,
+ &fb->bmi,
+ DIB_RGB_COLORS,
+ &DIBits,
+ NULL, 0);
+ hbmp = SelectObject(hmemDC, hbmp);
+ BitBlt(hdc,
+ 0,
+ 0,
+ fb->bmi.bmiHeader.biWidth,
+ fb->bmi.bmiHeader.biHeight,
+ hmemDC,
+ 0,
+ 0,
+ SRCCOPY);
+ /* Copy the bits */
+ CopyMemory(fb->frontbuffer, DIBits, buffer_size);
+ /* Clean up */
+ hbmp = SelectObject(hmemDC, hbmp);
+ DeleteDC(hmemDC);
+ DeleteObject(hbmp);
+ /* We're clean */
+ fb->flags ^= SW_FB_DIRTY_BITS;
+ }
+}
+
+static void GLAPIENTRY sw_db_ReadBuffer(GLenum mode)
+{
+ struct sw_context* ctx = (struct sw_context*)IntGetCurrentDHGLRC();
+
+ /* All good */
+ if(ctx->readmode == mode)
+ return;
+
+ /* We don't support stereoscopic formats */
+ if(mode == GL_FRONT)
+ mode = GL_FRONT_LEFT;
+
+ if(mode == GL_BACK)
+ mode = GL_BACK_LEFT;
+
+ /* Validate the asked mode */
+ if((mode != GL_FRONT_LEFT) || (mode != GL_BACK_LEFT))
+ {
+ ERR("Incompatble mode passed: %lx.\n", mode);
+ return;
+ }
+
+ /* Save it */
+ ctx->readmode = mode;
+}
+
+static void GLAPIENTRY sw_db_GetBooleanv(GLenum pname, GLboolean* params)
+{
+ struct sw_context* ctx = (struct sw_context*)IntGetCurrentDHGLRC();
+ switch(pname)
+ {
+ case GL_READ_BUFFER:
+ /* Well, it's never 0, but eh, the spec you know */
+ *params = (ctx->readmode != 0);
+ return;
+ default:
+ pGetBooleanv(pname, params);
+ return;
+ }
+}
+
+static void GLAPIENTRY sw_db_GetDoublev(GLenum pname, GLdouble* params)
+{
+ struct sw_context* ctx = (struct sw_context*)IntGetCurrentDHGLRC();
+ switch(pname)
+ {
+ case GL_READ_BUFFER:
+ *params = (GLdouble)ctx->readmode;
+ return;
+ default:
+ pGetDoublev(pname, params);
+ return;
+ }
+}
+
+static void GLAPIENTRY sw_db_GetFloatv(GLenum pname, GLfloat* params)
+{
+ struct sw_context* ctx = (struct sw_context*)IntGetCurrentDHGLRC();
+ switch(pname)
+ {
+ case GL_READ_BUFFER:
+ *params = (GLfloat)ctx->readmode;
+ return;
+ default:
+ pGetFloatv(pname, params);
+ return;
+ }
+}
+
+static void GLAPIENTRY sw_db_GetIntegerv(GLenum pname, GLint* params)
+{
+ struct sw_context* ctx = (struct sw_context*)IntGetCurrentDHGLRC();
+ switch(pname)
+ {
+ case GL_READ_BUFFER:
+ *params = ctx->readmode;
+ return;
+ default:
+ pGetIntegerv(pname, params);
+ return;
+ }
+}
+
+static void GLAPIENTRY sw_db_ReadPixels(
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ GLvoid *pixels
+)
+{
+ struct sw_context* ctx = (struct sw_context*)IntGetCurrentDHGLRC();
+ struct wgl_dc_data* dc_data = IntGetCurrentDcData();
+ struct sw_framebuffer* fb = dc_data->sw_data;
+
+ /* Quick path */
+ if(ctx->readmode == GL_BACK_LEFT)
+ {
+ pReadPixels(x, y, width, height, format, type, pixels);
+ return;
+ }
+
+ assert(ctx->readmode == GL_FRONT_LEFT);
+
+ /* Update frontbuffer */
+ if(fb->flags & SW_FB_DIRTY)
+ sw_db_update_frontbuffer(fb, IntGetCurrentDC());
+
+ /* Finish wahtever is going on on backbuffer */
+ pFinish();
+ /* Tell osmesa we changed the buffer */
+ pOSMesaMakeCurrent(ctx->mesa_ctx, fb->frontbuffer, GL_UNSIGNED_BYTE, width,
height);
+
+ /* Go ahead */
+ pReadPixels(x, y, width, height, format, type, pixels);
+
+ /* Go back to backbuffer operation */
+ pOSMesaMakeCurrent(ctx->mesa_ctx, fb->backbuffer, GL_UNSIGNED_BYTE, width,
height);
+}
+
+/* WGL <-> OSMesa functions */
static UINT index_from_format(struct wgl_dc_data* dc_data, INT format, BOOL*
doubleBuffered)
{
UINT index, nb_win_compat = 0, start_win_compat = 0;
@@ -230,7 +414,7 @@
{
struct sw_framebuffer* fb;
BOOL doubleBuffered;
- /* NOTE: we let the wgl implementation tracking the pixel format for us */
+
if(hMesaDll != NULL)
goto osmesa_loaded;
@@ -280,9 +464,27 @@
/* For completeness */
sw_table_db.cEntries = sw_table_sb.cEntries = OPENGL_VERSION_110_ENTRIES;
- /* We are not really single buffered. */
- pFinish = sw_table_sb.glDispatchTable.Finish;
- sw_table_sb.glDispatchTable.Finish = sw_sb_Finish;
+ /* We are not really single/double buffered. */
+#define SWAP_SB_FUNC(x) do \
+{ \
+ p##x = sw_table_sb.glDispatchTable.x; \
+ sw_table_sb.glDispatchTable.x = sw_sb_##x; \
+} while(0)
+ SWAP_SB_FUNC(Finish);
+#undef SWAP_SB_FUNC
+#define SWAP_DB_FUNC(x) do \
+{ \
+ p##x = sw_table_db.glDispatchTable.x; \
+ sw_table_db.glDispatchTable.x = sw_db_##x; \
+} while(0)
+ SWAP_DB_FUNC(ReadBuffer);
+ SWAP_DB_FUNC(ReadPixels);
+ SWAP_DB_FUNC(GetBooleanv);
+ SWAP_DB_FUNC(GetIntegerv);
+ SWAP_DB_FUNC(GetFloatv);
+ SWAP_DB_FUNC(GetDoublev);
+#undef SWAP_DB_FUNC
+
/* OpenGL spec: flush == all pending commands are sent to the server,
* and the client will receive the data in finished time.
* We will call this finish in our case */
@@ -320,7 +522,9 @@
HeapFree( GetProcessHeap(), 0, context );
return NULL;
}
+ /* Set defaults */
context->hook = NULL;
+ context->readmode = GL_BACK_LEFT;
return (DHGLRC)context;
}
@@ -352,7 +556,6 @@
}
}
-#define WIDTH_BYTES_ALIGN32(cx, bpp) ((((cx) * (bpp) + 31) & ~31) >> 3)
static
LRESULT CALLBACK
sw_call_window_proc(
@@ -396,6 +599,9 @@
height = client_rect.bottom - client_rect.top;
/* Do not reallocate for minimized windows */
if(width <= 0 || height <= 0)
+ goto end;
+ /* Do not bother with unchanged size */
+ if(width == fb->bmi.bmiHeader.biWidth && height ==
fb->bmi.bmiHeader.biHeight)
goto end;
/* Resize the buffer accordingly */
widthBytes = WIDTH_BYTES_ALIGN32(width,
pixel_formats[fb->format_index].color_bits);
@@ -407,6 +613,8 @@
/* Re-enable osmesa */
pOSMesaMakeCurrent(ctx->mesa_ctx, fb->bits, GL_UNSIGNED_BYTE, width,
height);
pOSMesaPixelStore(OSMESA_ROW_LENGTH, widthBytes * 8 /
pixel_formats[fb->format_index].color_bits);
+ /* Mark dirty bit acordingly */
+ fb->flags |= SW_FB_DIRTY_SIZE;
}
}
@@ -481,6 +689,7 @@
if(bits)
{
+ assert(!(fb->flags & SW_FB_DOUBLEBUFFERED));
if(fb->flags & SW_FB_FREE_BITS)
{
fb->flags ^= SW_FB_FREE_BITS;
@@ -489,14 +698,14 @@
fb->flags |= SW_FB_DIBSECTION;
fb->bits = bits;
}
- else
+ else if((width != fb->bmi.bmiHeader.biWidth) || (height !=
fb->bmi.bmiHeader.biHeight))
{
widthBytes = WIDTH_BYTES_ALIGN32(width,
pixel_formats[fb->format_index].color_bits);
if(fb->flags & SW_FB_FREE_BITS)
fb->bits = HeapReAlloc(GetProcessHeap(), 0, fb->bits, widthBytes *
height);
else
fb->bits = HeapAlloc(GetProcessHeap(), 0, widthBytes * height);
- fb->flags |= SW_FB_FREE_BITS;
+ fb->flags |= (SW_FB_FREE_BITS | SW_FB_DIRTY_SIZE);
fb->flags &= ~SW_FB_DIBSECTION;
}
@@ -572,6 +781,9 @@
/* Finish before swapping */
pFinish();
+ /* We are now dirty */
+ fb->flags |= SW_FB_DIRTY_BITS;
+
return (SetDIBitsToDevice(hdc,
0,
0,