Hi all, This patch should not be dependant of any others... But to prevent line number errors, better to commit it after the 5 -> 9 series (yeah, the attachements are numbered to ease tracking :-) ). Changelog: - start of support for device locking / unlocking via glReadPixels / glDrawPixels interface (slow but should be enough for a start) - implement one vertex case for the D3D3/7 DrawPrimitive functions - fix a missing \n in a TRACE call Lionel -- Lionel Ulmer - http://www.bbrox.org/
--- ../wine_work_base/dlls/ddraw/d3dviewport.c Sat Nov 23 20:45:28 2002 +++ dlls/ddraw/d3dviewport.c Fri Nov 29 21:52:36 2002 @@ -438,7 +438,7 @@ ((dwColor >> 8) & 0xFF) / 255.0, ((dwColor >> 0) & 0xFF) / 255.0, ((dwColor >> 24) & 0xFF) / 255.0); - TRACE("Color value (ARGB) : %08lx", dwColor); + TRACE("Color value (ARGB) : %08lx\n", dwColor); } glClear(bitfield); --- ../wine_work_base/dlls/ddraw/ddraw_private.h Wed Nov 27 23:01:56 2002 +++ dlls/ddraw/ddraw_private.h Fri Nov 29 21:58:53 2002 @@ -368,4 +368,28 @@ extern void DDRAW_dump_lockflag(DWORD lockflag); extern void DDRAW_dump_DDCOLORKEY(const DDCOLORKEY *in); extern void DDRAW_dump_DDCAPS(const DDCAPS *lpcaps); + +/* Used for generic dumping */ +typedef struct +{ + DWORD val; + const char* name; +} flag_info; + +#define FE(x) { x, #x } + +typedef struct +{ + DWORD val; + const char* name; + void (*func)(const void *); + ptrdiff_t offset; +} member_info; + +#define DDRAW_dump_flags(flags,names,num_names) DDRAW_dump_flags_(flags, names, num_names, 1) +#define ME(x,f,e) { x, #x, (void (*)(const void *))(f), offsetof(STRUCT, e) } + +extern void DDRAW_dump_flags_(DWORD flags, const flag_info* names, size_t num_names, int newline); +extern void DDRAW_dump_members(DWORD flags, const void* data, const member_info* mems, size_t num_mems); + #endif /* __WINE_DLLS_DDRAW_DDRAW_PRIVATE_H */ --- ../wine_work_base/dlls/ddraw/helper.c Wed Nov 27 23:01:56 2002 +++ dlls/ddraw/helper.c Fri Nov 29 21:58:21 2002 @@ -39,29 +39,8 @@ /****************************************************************************** * debug output functions */ -typedef struct -{ - DWORD val; - const char* name; -} flag_info; - -#define FE(x) { x, #x } - -typedef struct -{ - DWORD val; - const char* name; - void (*func)(const void *); - ptrdiff_t offset; -} member_info; - -#define ME(x,f,e) { x, #x, (void (*)(const void *))(f), offsetof(STRUCT, e) } - -#define DDRAW_dump_flags(flags,names,num_names) \ - DDRAW_dump_flags_(flags, names, num_names, 1) - -static void DDRAW_dump_flags_(DWORD flags, const flag_info* names, - size_t num_names, int newline) +void DDRAW_dump_flags_(DWORD flags, const flag_info* names, + size_t num_names, int newline) { unsigned int i; @@ -74,8 +53,8 @@ DPRINTF("\n"); } -static void DDRAW_dump_members(DWORD flags, const void* data, - const member_info* mems, size_t num_mems) +void DDRAW_dump_members(DWORD flags, const void* data, + const member_info* mems, size_t num_mems) { unsigned int i; --- ../wine_work_base/dlls/ddraw/d3ddevice/mesa.c Wed Nov 27 23:05:15 2002 +++ dlls/ddraw/d3ddevice/mesa.c Fri Nov 29 23:14:18 2002 @@ -607,6 +607,45 @@ return DD_OK; } +inline static void draw_primitive_start_GL(D3DPRIMITIVETYPE d3dpt) +{ + switch (d3dpt) { + case D3DPT_POINTLIST: + TRACE("Start POINTS\n"); + glBegin(GL_POINTS); + break; + + case D3DPT_LINELIST: + TRACE("Start LINES\n"); + glBegin(GL_LINES); + break; + + case D3DPT_LINESTRIP: + TRACE("Start LINE_STRIP\n"); + glBegin(GL_LINE_STRIP); + break; + + case D3DPT_TRIANGLELIST: + TRACE("Start TRIANGLES\n"); + glBegin(GL_TRIANGLES); + break; + + case D3DPT_TRIANGLESTRIP: + TRACE("Start TRIANGLE_STRIP\n"); + glBegin(GL_TRIANGLE_STRIP); + break; + + case D3DPT_TRIANGLEFAN: + TRACE("Start TRIANGLE_FAN\n"); + glBegin(GL_TRIANGLE_FAN); + break; + + default: + TRACE("Unhandled primitive\n"); + break; + } +} + inline static void draw_primitive(IDirect3DDeviceGLImpl *glThis, DWORD maxvert, WORD *index, D3DVERTEXTYPE d3dvt, D3DPRIMITIVETYPE d3dpt, void *lpvertex) { @@ -684,42 +723,8 @@ glThis->vertex_type = d3dvt; } - switch (d3dpt) { - case D3DPT_POINTLIST: - TRACE("Start POINTS\n"); - glBegin(GL_POINTS); - break; - - case D3DPT_LINELIST: - TRACE("Start LINES\n"); - glBegin(GL_LINES); - break; - - case D3DPT_LINESTRIP: - TRACE("Start LINE_STRIP\n"); - glBegin(GL_LINE_STRIP); - break; - - case D3DPT_TRIANGLELIST: - TRACE("Start TRIANGLES\n"); - glBegin(GL_TRIANGLES); - break; - - case D3DPT_TRIANGLESTRIP: - TRACE("Start TRIANGLE_STRIP\n"); - glBegin(GL_TRIANGLE_STRIP); - break; - - case D3DPT_TRIANGLEFAN: - TRACE("Start TRIANGLE_FAN\n"); - glBegin(GL_TRIANGLE_FAN); - break; - - default: - TRACE("Unhandled primitive\n"); - break; - } - + draw_primitive_start_GL(d3dpt); + /* Draw the primitives */ for (vx_index = 0; vx_index < maxvert; vx_index++) { switch (d3dvt) { @@ -748,9 +753,10 @@ D3DTLVERTEX *vx = ((D3DTLVERTEX *) lpvertex) + (index == 0 ? vx_index : index[vx_index]); DWORD col = vx->u5.color; - glColor3f(((col >> 16) & 0xFF) / 255.0, - ((col >> 8) & 0xFF) / 255.0, - ((col >> 0) & 0xFF) / 255.0); + glColor4ub((col >> 24) & 0xFF, + (col >> 16) & 0xFF, + (col >> 8) & 0xFF, + (col >> 0) & 0xFF); glTexCoord2f(vx->u7.tu, vx->u8.tv); if (vx->u4.rhw < 0.01) glVertex3f(vx->u1.sx, @@ -835,6 +841,131 @@ return ret_value; } +static void dump_flexible_vertex(DWORD d3dvtVertexType) +{ + static const flag_info flags[] = { + FE(D3DFVF_NORMAL), + FE(D3DFVF_RESERVED1), + FE(D3DFVF_DIFFUSE), + FE(D3DFVF_SPECULAR) + }; + if (d3dvtVertexType & D3DFVF_RESERVED0) DPRINTF("D3DFVF_RESERVED0 "); + switch (d3dvtVertexType & D3DFVF_POSITION_MASK) { +#define GEN_CASE(a) case a: DPRINTF(#a " "); break + GEN_CASE(D3DFVF_XYZ); + GEN_CASE(D3DFVF_XYZRHW); + GEN_CASE(D3DFVF_XYZB1); + GEN_CASE(D3DFVF_XYZB2); + GEN_CASE(D3DFVF_XYZB3); + GEN_CASE(D3DFVF_XYZB4); + GEN_CASE(D3DFVF_XYZB5); + } + DDRAW_dump_flags_(d3dvtVertexType, flags, sizeof(flags)/sizeof(flags[0]), FALSE); + switch (d3dvtVertexType & D3DFVF_TEXCOUNT_MASK) { + GEN_CASE(D3DFVF_TEX0); + GEN_CASE(D3DFVF_TEX1); + GEN_CASE(D3DFVF_TEX2); + GEN_CASE(D3DFVF_TEX3); + GEN_CASE(D3DFVF_TEX4); + GEN_CASE(D3DFVF_TEX5); + GEN_CASE(D3DFVF_TEX6); + GEN_CASE(D3DFVF_TEX7); + GEN_CASE(D3DFVF_TEX8); + } +#undef GEN_CASE + DPRINTF("\n"); +} + +/* Some types used by the fast paths... */ +typedef struct { + float x, y, z; + float nx, ny, nz; + DWORD dwDiffuseRGBA; + float tu1, tv1; +} D3DFVF_VERTEX_1; + +static void draw_primitive_7(IDirect3DDeviceImpl *This, + D3DPRIMITIVETYPE d3dptPrimitiveType, + DWORD d3dvtVertexType, + LPVOID lpvVertices, + DWORD dwVertexCount, + LPWORD dwIndices, + DWORD dwIndexCount, + DWORD dwFlags) +{ + if (TRACE_ON(ddraw)) { + TRACE(" Vertex format : "); dump_flexible_vertex(d3dvtVertexType); + } + + ENTER_GL(); + draw_primitive_start_GL(d3dptPrimitiveType); + + /* Some fast paths first before the generic case.... */ + if (d3dvtVertexType == D3DFVF_VERTEX) { + D3DFVF_VERTEX_1 *vertices = (D3DFVF_VERTEX_1 *) lpvVertices; + int index; + + for (index = 0; index < dwIndexCount; index++) { + int i = (dwIndices == NULL) ? index : dwIndices[index]; + + glNormal3f(vertices[i].nx, vertices[i].ny, vertices[i].nz); + glTexCoord2f(vertices[i].tu1, vertices[i].tv1); + glColor4ub((vertices[i].dwDiffuseRGBA >> 24) & 0xFF, + (vertices[i].dwDiffuseRGBA >> 16) & 0xFF, + (vertices[i].dwDiffuseRGBA >> 8) & 0xFF, + (vertices[i].dwDiffuseRGBA >> 0) & 0xFF); + glVertex3f(vertices[i].x, vertices[i].y, vertices[i].z); + TRACE(" %f %f %f / %f %f %f (%02lx %02lx %02lx %02lx) (%f %f)\n", + vertices[i].x, vertices[i].y, vertices[i].z, + vertices[i].nx, vertices[i].ny, vertices[i].nz, + (vertices[i].dwDiffuseRGBA >> 24) & 0xFF, + (vertices[i].dwDiffuseRGBA >> 16) & 0xFF, + (vertices[i].dwDiffuseRGBA >> 8) & 0xFF, + (vertices[i].dwDiffuseRGBA >> 0) & 0xFF, + vertices[i].tu1, vertices[i].tv1); + } + } + + glEnd(); + LEAVE_GL(); + TRACE("End\n"); +} + + +HRESULT WINAPI +GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive(LPDIRECT3DDEVICE7 iface, + D3DPRIMITIVETYPE d3dptPrimitiveType, + DWORD d3dvtVertexType, + LPVOID lpvVertices, + DWORD dwVertexCount, + DWORD dwFlags) +{ + ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface); + TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwFlags); + + draw_primitive_7(This, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, NULL, dwVertexCount, dwFlags); + + return DD_OK; +} + +HRESULT WINAPI +GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive(LPDIRECT3DDEVICE7 iface, + D3DPRIMITIVETYPE d3dptPrimitiveType, + DWORD d3dvtVertexType, + LPVOID lpvVertices, + DWORD dwVertexCount, + LPWORD dwIndices, + DWORD dwIndexCount, + DWORD dwFlags) +{ + ICOM_THIS_FROM(IDirect3DDeviceImpl, IDirect3DDevice7, iface); + TRACE("(%p/%p)->(%08x,%08lx,%p,%08lx,%p,%08lx,%08lx)\n", This, iface, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags); + + draw_primitive_7(This, d3dptPrimitiveType, d3dvtVertexType, lpvVertices, dwVertexCount, dwIndices, dwIndexCount, dwFlags); + + return DD_OK; +} + #if !defined(__STRICT_ANSI__) && defined(__GNUC__) # define XCAST(fun) (typeof(VTABLE_IDirect3DDevice7.fun)) #else @@ -869,8 +1000,8 @@ XCAST(BeginStateBlock) Main_IDirect3DDeviceImpl_7_BeginStateBlock, XCAST(EndStateBlock) Main_IDirect3DDeviceImpl_7_EndStateBlock, XCAST(PreLoad) Main_IDirect3DDeviceImpl_7_PreLoad, - XCAST(DrawPrimitive) Main_IDirect3DDeviceImpl_7_3T_DrawPrimitive, - XCAST(DrawIndexedPrimitive) Main_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive, + XCAST(DrawPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawPrimitive, + XCAST(DrawIndexedPrimitive) GL_IDirect3DDeviceImpl_7_3T_DrawIndexedPrimitive, XCAST(SetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_SetClipStatus, XCAST(GetClipStatus) Main_IDirect3DDeviceImpl_7_3T_2T_GetClipStatus, XCAST(DrawPrimitiveStrided) Main_IDirect3DDeviceImpl_7_3T_DrawPrimitiveStrided, @@ -1044,8 +1175,97 @@ #undef XCAST #endif +/* TODO for both these functions : + - change / restore OpenGL parameters for pictures transfers in case they are ever modified + by other OpenGL code in D3D + - handle the case where no 'Begin / EndScene' was done between two locks + - handle the rectangles in the unlock too +*/ +static void d3ddevice_lock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect, DWORD dwFlags) +{ + /* First, check if we need to do anything */ + if ((This->lastlocktype & DDLOCK_WRITEONLY) == 0) { + GLenum buffer_type; + GLenum prev_read; + RECT loc_rect; + + ENTER_GL(); + + glGetIntegerv(GL_READ_BUFFER, &prev_read); + glFlush(); + + WARN(" application does a lock on a 3D surface - expect slow downs.\n"); + if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) { + /* Application wants to lock the front buffer */ + glReadBuffer(GL_FRONT); + } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) { + /* Application wants to lock the back buffer */ + glReadBuffer(GL_BACK); + } else { + WARN(" do not support 3D surface locking for this surface type - trying to use default buffer.\n"); + } + if (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) { + buffer_type = GL_UNSIGNED_SHORT_5_6_5; + } else { + WARN(" unsupported pixel format.\n"); + LEAVE_GL(); + return; + } + if (pRect == NULL) { + loc_rect.top = 0; + loc_rect.left = 0; + loc_rect.bottom = This->surface_desc.dwHeight; + loc_rect.right = This->surface_desc.dwWidth; + } else { + loc_rect = *pRect; + } + glReadPixels(loc_rect.left, loc_rect.top, loc_rect.right, loc_rect.bottom, + GL_RGB, buffer_type, ((char *)This->surface_desc.lpSurface + + loc_rect.top * This->surface_desc.u1.lPitch + + loc_rect.left * GET_BPP(This->surface_desc))); + glReadBuffer(prev_read); + LEAVE_GL(); + } +} +static void d3ddevice_unlock_update(IDirectDrawSurfaceImpl* This, LPCRECT pRect) +{ + /* First, check if we need to do anything */ + if ((This->lastlocktype & DDLOCK_READONLY) == 0) { + GLenum buffer_type; + GLenum prev_draw;; + + ENTER_GL(); + + glGetIntegerv(GL_DRAW_BUFFER, &prev_draw); + + WARN(" application does an unlock on a 3D surface - expect slow downs.\n"); + if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_FRONTBUFFER|DDSCAPS_PRIMARYSURFACE)) != 0) { + /* Application wants to lock the front buffer */ + glDrawBuffer(GL_FRONT); + } else if ((This->surface_desc.ddsCaps.dwCaps & (DDSCAPS_BACKBUFFER)) == (DDSCAPS_BACKBUFFER)) { + /* Application wants to lock the back buffer */ + glDrawBuffer(GL_BACK); + } else { + WARN(" do not support 3D surface locking for this surface type - trying to use default buffer.\n"); + } + + if (This->surface_desc.u4.ddpfPixelFormat.u1.dwRGBBitCount == 16) { + buffer_type = GL_UNSIGNED_SHORT_5_6_5; + } else { + WARN(" unsupported pixel format.\n"); + LEAVE_GL(); + return; + } + + glDrawPixels(This->surface_desc.dwWidth, This->surface_desc.dwHeight, + GL_RGB, buffer_type, This->surface_desc.lpSurface); + glDrawBuffer(prev_draw); + + LEAVE_GL(); + } +} HRESULT d3ddevice_create(IDirect3DDeviceImpl **obj, IDirect3DImpl *d3d, IDirectDrawSurfaceImpl *surface) @@ -1057,6 +1277,7 @@ XVisualInfo *vis; int num; XVisualInfo template; + GLenum buffer; object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirect3DDeviceGLImpl)); if (object == NULL) return DDERR_OUTOFMEMORY; @@ -1070,14 +1291,14 @@ object->current_viewport = NULL; object->current_texture = NULL; object->set_context = set_context; - + TRACE(" creating OpenGL device for surface = %p, d3d = %p\n", surface, d3d); device_context = GetDC(surface->ddraw_owner->window); gl_object->display = get_display(device_context); gl_object->drawable = get_drawable(device_context); ReleaseDC(surface->ddraw_owner->window,device_context); - + ENTER_GL(); template.visualid = (VisualID)GetPropA( GetDesktopWindow(), "__wine_x11_visual_id" ); vis = XGetVisualInfo(gl_object->display, VisualIDMask, &template, &num); @@ -1105,12 +1326,29 @@ /* Look for the front buffer and override its surface's Flip method (if in double buffering) */ for (surf = surface; surf != NULL; surf = surf->surface_owner) { if ((surf->surface_desc.ddsCaps.dwCaps&(DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) == (DDSCAPS_FLIP|DDSCAPS_FRONTBUFFER)) { - surface->surface_owner->aux_ctx = (LPVOID) gl_object->display; - surface->surface_owner->aux_data = (LPVOID) gl_object->drawable; - surface->surface_owner->aux_flip = opengl_flip; + surf->aux_ctx = (LPVOID) gl_object->display; + surf->aux_data = (LPVOID) gl_object->drawable; + surf->aux_flip = opengl_flip; + buffer = GL_BACK; break; } } + /* We are not doing any double buffering.. Then force OpenGL to draw on the front buffer */ + if (surf == NULL) { + TRACE(" no double buffering : drawing on the front buffer\n"); + buffer = GL_FRONT; + } + + for (surf = surface; surf->prev_attached != NULL; surf = surf->prev_attached) ; + for (; surf != NULL; surf = surf->next_attached) { + if (((surf->surface_desc.ddsCaps.dwCaps & (DDSCAPS_3DDEVICE)) == (DDSCAPS_3DDEVICE)) && + ((surf->surface_desc.ddsCaps.dwCaps & (DDSCAPS_ZBUFFER)) != (DDSCAPS_ZBUFFER))) { + /* Override the Lock / Unlock function for all these surfaces */ + surf->lock_update = d3ddevice_lock_update; + surf->unlock_update = d3ddevice_unlock_update; + } + surf->d3ddevice = object; + } gl_object->render_state.src = GL_ONE; gl_object->render_state.dst = GL_ZERO; @@ -1135,6 +1373,9 @@ TRACE(" current context set\n"); glClearColor(0.0, 0.0, 0.0, 0.0); glColor3f(1.0, 1.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glDrawBuffer(buffer); + /* glDisable(GL_DEPTH_TEST); Need here to check for the presence of a ZBuffer and to reenable it when the ZBuffer is attached */ LEAVE_GL(); /* fill_device_capabilities(d3d->ddraw); */