wined3d: Only invalidate the INDRAWABLE location for onscreen surfaces in surface_rea...
[wine] / dlls / wined3d / surface.c
1 /*
2  * IWineD3DSurface Implementation
3  *
4  * Copyright 1997-2000 Marcus Meissner
5  * Copyright 1998-2000 Lionel Ulmer
6  * Copyright 2000-2001 TransGaming Technologies Inc.
7  * Copyright 2002-2005 Jason Edmeades
8  * Copyright 2002-2003 Raphael Junqueira
9  * Copyright 2004 Christian Costa
10  * Copyright 2005 Oliver Stieber
11  * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
12  * Copyright 2007-2008 Henri Verbeet
13  * Copyright 2006-2008 Roderick Colenbrander
14  * Copyright 2009-2011 Henri Verbeet for CodeWeavers
15  *
16  * This library is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU Lesser General Public
18  * License as published by the Free Software Foundation; either
19  * version 2.1 of the License, or (at your option) any later version.
20  *
21  * This library is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * Lesser General Public License for more details.
25  *
26  * You should have received a copy of the GNU Lesser General Public
27  * License along with this library; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29  */
30
31 #include "config.h"
32 #include "wine/port.h"
33 #include "wined3d_private.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
36 WINE_DECLARE_DEBUG_CHANNEL(d3d);
37
38 static void surface_cleanup(IWineD3DSurfaceImpl *This)
39 {
40     TRACE("(%p) : Cleaning up.\n", This);
41
42     if (This->texture_name || (This->flags & SFLAG_PBO) || !list_empty(&This->renderbuffers))
43     {
44         const struct wined3d_gl_info *gl_info;
45         renderbuffer_entry_t *entry, *entry2;
46         struct wined3d_context *context;
47
48         context = context_acquire(This->resource.device, NULL);
49         gl_info = context->gl_info;
50
51         ENTER_GL();
52
53         if (This->texture_name)
54         {
55             TRACE("Deleting texture %u.\n", This->texture_name);
56             glDeleteTextures(1, &This->texture_name);
57         }
58
59         if (This->flags & SFLAG_PBO)
60         {
61             TRACE("Deleting PBO %u.\n", This->pbo);
62             GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
63         }
64
65         LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry)
66         {
67             TRACE("Deleting renderbuffer %u.\n", entry->id);
68             gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
69             HeapFree(GetProcessHeap(), 0, entry);
70         }
71
72         LEAVE_GL();
73
74         context_release(context);
75     }
76
77     if (This->flags & SFLAG_DIBSECTION)
78     {
79         /* Release the DC. */
80         SelectObject(This->hDC, This->dib.holdbitmap);
81         DeleteDC(This->hDC);
82         /* Release the DIB section. */
83         DeleteObject(This->dib.DIBsection);
84         This->dib.bitmap_data = NULL;
85         This->resource.allocatedMemory = NULL;
86     }
87
88     if (This->flags & SFLAG_USERPTR) IWineD3DSurface_SetMem((IWineD3DSurface *)This, NULL);
89     if (This->overlay_dest) list_remove(&This->overlay_entry);
90
91     HeapFree(GetProcessHeap(), 0, This->palette9);
92
93     resource_cleanup(&This->resource);
94 }
95
96 void surface_set_container(IWineD3DSurfaceImpl *surface, enum wined3d_container_type type, void *container)
97 {
98     TRACE("surface %p, container %p.\n", surface, container);
99
100     if (!container && type != WINED3D_CONTAINER_NONE)
101         ERR("Setting NULL container of type %#x.\n", type);
102
103     if (type == WINED3D_CONTAINER_SWAPCHAIN)
104     {
105         surface->get_drawable_size = get_drawable_size_swapchain;
106     }
107     else
108     {
109         switch (wined3d_settings.offscreen_rendering_mode)
110         {
111             case ORM_FBO:
112                 surface->get_drawable_size = get_drawable_size_fbo;
113                 break;
114
115             case ORM_BACKBUFFER:
116                 surface->get_drawable_size = get_drawable_size_backbuffer;
117                 break;
118
119             default:
120                 ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
121                 return;
122         }
123     }
124
125     surface->container.type = type;
126     surface->container.u.base = container;
127 }
128
129 struct blt_info
130 {
131     GLenum binding;
132     GLenum bind_target;
133     enum tex_types tex_type;
134     GLfloat coords[4][3];
135 };
136
137 struct float_rect
138 {
139     float l;
140     float t;
141     float r;
142     float b;
143 };
144
145 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
146 {
147     f->l = ((r->left * 2.0f) / w) - 1.0f;
148     f->t = ((r->top * 2.0f) / h) - 1.0f;
149     f->r = ((r->right * 2.0f) / w) - 1.0f;
150     f->b = ((r->bottom * 2.0f) / h) - 1.0f;
151 }
152
153 static void surface_get_blt_info(GLenum target, const RECT *rect, GLsizei w, GLsizei h, struct blt_info *info)
154 {
155     GLfloat (*coords)[3] = info->coords;
156     struct float_rect f;
157
158     switch (target)
159     {
160         default:
161             FIXME("Unsupported texture target %#x\n", target);
162             /* Fall back to GL_TEXTURE_2D */
163         case GL_TEXTURE_2D:
164             info->binding = GL_TEXTURE_BINDING_2D;
165             info->bind_target = GL_TEXTURE_2D;
166             info->tex_type = tex_2d;
167             coords[0][0] = (float)rect->left / w;
168             coords[0][1] = (float)rect->top / h;
169             coords[0][2] = 0.0f;
170
171             coords[1][0] = (float)rect->right / w;
172             coords[1][1] = (float)rect->top / h;
173             coords[1][2] = 0.0f;
174
175             coords[2][0] = (float)rect->left / w;
176             coords[2][1] = (float)rect->bottom / h;
177             coords[2][2] = 0.0f;
178
179             coords[3][0] = (float)rect->right / w;
180             coords[3][1] = (float)rect->bottom / h;
181             coords[3][2] = 0.0f;
182             break;
183
184         case GL_TEXTURE_RECTANGLE_ARB:
185             info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
186             info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
187             info->tex_type = tex_rect;
188             coords[0][0] = rect->left;  coords[0][1] = rect->top;       coords[0][2] = 0.0f;
189             coords[1][0] = rect->right; coords[1][1] = rect->top;       coords[1][2] = 0.0f;
190             coords[2][0] = rect->left;  coords[2][1] = rect->bottom;    coords[2][2] = 0.0f;
191             coords[3][0] = rect->right; coords[3][1] = rect->bottom;    coords[3][2] = 0.0f;
192             break;
193
194         case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
195             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
196             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
197             info->tex_type = tex_cube;
198             cube_coords_float(rect, w, h, &f);
199
200             coords[0][0] =  1.0f;   coords[0][1] = -f.t;   coords[0][2] = -f.l;
201             coords[1][0] =  1.0f;   coords[1][1] = -f.t;   coords[1][2] = -f.r;
202             coords[2][0] =  1.0f;   coords[2][1] = -f.b;   coords[2][2] = -f.l;
203             coords[3][0] =  1.0f;   coords[3][1] = -f.b;   coords[3][2] = -f.r;
204             break;
205
206         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
207             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
208             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
209             info->tex_type = tex_cube;
210             cube_coords_float(rect, w, h, &f);
211
212             coords[0][0] = -1.0f;   coords[0][1] = -f.t;   coords[0][2] = f.l;
213             coords[1][0] = -1.0f;   coords[1][1] = -f.t;   coords[1][2] = f.r;
214             coords[2][0] = -1.0f;   coords[2][1] = -f.b;   coords[2][2] = f.l;
215             coords[3][0] = -1.0f;   coords[3][1] = -f.b;   coords[3][2] = f.r;
216             break;
217
218         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
219             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
220             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
221             info->tex_type = tex_cube;
222             cube_coords_float(rect, w, h, &f);
223
224             coords[0][0] = f.l;   coords[0][1] =  1.0f;   coords[0][2] = f.t;
225             coords[1][0] = f.r;   coords[1][1] =  1.0f;   coords[1][2] = f.t;
226             coords[2][0] = f.l;   coords[2][1] =  1.0f;   coords[2][2] = f.b;
227             coords[3][0] = f.r;   coords[3][1] =  1.0f;   coords[3][2] = f.b;
228             break;
229
230         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
231             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
232             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
233             info->tex_type = tex_cube;
234             cube_coords_float(rect, w, h, &f);
235
236             coords[0][0] = f.l;   coords[0][1] = -1.0f;   coords[0][2] = -f.t;
237             coords[1][0] = f.r;   coords[1][1] = -1.0f;   coords[1][2] = -f.t;
238             coords[2][0] = f.l;   coords[2][1] = -1.0f;   coords[2][2] = -f.b;
239             coords[3][0] = f.r;   coords[3][1] = -1.0f;   coords[3][2] = -f.b;
240             break;
241
242         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
243             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
244             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
245             info->tex_type = tex_cube;
246             cube_coords_float(rect, w, h, &f);
247
248             coords[0][0] = f.l;   coords[0][1] = -f.t;   coords[0][2] =  1.0f;
249             coords[1][0] = f.r;   coords[1][1] = -f.t;   coords[1][2] =  1.0f;
250             coords[2][0] = f.l;   coords[2][1] = -f.b;   coords[2][2] =  1.0f;
251             coords[3][0] = f.r;   coords[3][1] = -f.b;   coords[3][2] =  1.0f;
252             break;
253
254         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
255             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
256             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
257             info->tex_type = tex_cube;
258             cube_coords_float(rect, w, h, &f);
259
260             coords[0][0] = -f.l;   coords[0][1] = -f.t;   coords[0][2] = -1.0f;
261             coords[1][0] = -f.r;   coords[1][1] = -f.t;   coords[1][2] = -1.0f;
262             coords[2][0] = -f.l;   coords[2][1] = -f.b;   coords[2][2] = -1.0f;
263             coords[3][0] = -f.r;   coords[3][1] = -f.b;   coords[3][2] = -1.0f;
264             break;
265     }
266 }
267
268 static inline void surface_get_rect(IWineD3DSurfaceImpl *This, const RECT *rect_in, RECT *rect_out)
269 {
270     if (rect_in)
271         *rect_out = *rect_in;
272     else
273     {
274         rect_out->left = 0;
275         rect_out->top = 0;
276         rect_out->right = This->resource.width;
277         rect_out->bottom = This->resource.height;
278     }
279 }
280
281 /* GL locking and context activation is done by the caller */
282 void draw_textured_quad(IWineD3DSurfaceImpl *src_surface, const RECT *src_rect, const RECT *dst_rect, WINED3DTEXTUREFILTERTYPE Filter)
283 {
284     struct blt_info info;
285
286     surface_get_blt_info(src_surface->texture_target, src_rect, src_surface->pow2Width, src_surface->pow2Height, &info);
287
288     glEnable(info.bind_target);
289     checkGLcall("glEnable(bind_target)");
290
291     /* Bind the texture */
292     glBindTexture(info.bind_target, src_surface->texture_name);
293     checkGLcall("glBindTexture");
294
295     /* Filtering for StretchRect */
296     glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER,
297             wined3d_gl_mag_filter(magLookup, Filter));
298     checkGLcall("glTexParameteri");
299     glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER,
300             wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
301     checkGLcall("glTexParameteri");
302     glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
303     glTexParameteri(info.bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
304     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
305     checkGLcall("glTexEnvi");
306
307     /* Draw a quad */
308     glBegin(GL_TRIANGLE_STRIP);
309     glTexCoord3fv(info.coords[0]);
310     glVertex2i(dst_rect->left, dst_rect->top);
311
312     glTexCoord3fv(info.coords[1]);
313     glVertex2i(dst_rect->right, dst_rect->top);
314
315     glTexCoord3fv(info.coords[2]);
316     glVertex2i(dst_rect->left, dst_rect->bottom);
317
318     glTexCoord3fv(info.coords[3]);
319     glVertex2i(dst_rect->right, dst_rect->bottom);
320     glEnd();
321
322     /* Unbind the texture */
323     glBindTexture(info.bind_target, 0);
324     checkGLcall("glBindTexture(info->bind_target, 0)");
325
326     /* We changed the filtering settings on the texture. Inform the
327      * container about this to get the filters reset properly next draw. */
328     if (src_surface->container.type == WINED3D_CONTAINER_TEXTURE)
329     {
330         struct wined3d_texture *texture = src_surface->container.u.texture;
331         texture->texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
332         texture->texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
333         texture->texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE;
334     }
335 }
336
337 static HRESULT surface_create_dib_section(IWineD3DSurfaceImpl *surface)
338 {
339     const struct wined3d_format *format = surface->resource.format;
340     SYSTEM_INFO sysInfo;
341     BITMAPINFO *b_info;
342     int extraline = 0;
343     DWORD *masks;
344     UINT usage;
345     HDC dc;
346
347     TRACE("surface %p.\n", surface);
348
349     if (!(format->flags & WINED3DFMT_FLAG_GETDC))
350     {
351         WARN("Cannot use GetDC on a %s surface.\n", debug_d3dformat(format->id));
352         return WINED3DERR_INVALIDCALL;
353     }
354
355     switch (format->byte_count)
356     {
357         case 2:
358         case 4:
359             /* Allocate extra space to store the RGB bit masks. */
360             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
361             break;
362
363         case 3:
364             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
365             break;
366
367         default:
368             /* Allocate extra space for a palette. */
369             b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
370                     sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1 << (format->byte_count * 8)));
371             break;
372     }
373
374     if (!b_info)
375         return E_OUTOFMEMORY;
376
377     /* Some applications access the surface in via DWORDs, and do not take
378      * the necessary care at the end of the surface. So we need at least
379      * 4 extra bytes at the end of the surface. Check against the page size,
380      * if the last page used for the surface has at least 4 spare bytes we're
381      * safe, otherwise add an extra line to the DIB section. */
382     GetSystemInfo(&sysInfo);
383     if( ((surface->resource.size + 3) % sysInfo.dwPageSize) < 4)
384     {
385         extraline = 1;
386         TRACE("Adding an extra line to the DIB section.\n");
387     }
388
389     b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
390     /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
391     b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface) / format->byte_count;
392     b_info->bmiHeader.biHeight = -surface->resource.height - extraline;
393     b_info->bmiHeader.biSizeImage = (surface->resource.height + extraline)
394             * IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);
395     b_info->bmiHeader.biPlanes = 1;
396     b_info->bmiHeader.biBitCount = format->byte_count * 8;
397
398     b_info->bmiHeader.biXPelsPerMeter = 0;
399     b_info->bmiHeader.biYPelsPerMeter = 0;
400     b_info->bmiHeader.biClrUsed = 0;
401     b_info->bmiHeader.biClrImportant = 0;
402
403     /* Get the bit masks */
404     masks = (DWORD *)b_info->bmiColors;
405     switch (surface->resource.format->id)
406     {
407         case WINED3DFMT_B8G8R8_UNORM:
408             usage = DIB_RGB_COLORS;
409             b_info->bmiHeader.biCompression = BI_RGB;
410             break;
411
412         case WINED3DFMT_B5G5R5X1_UNORM:
413         case WINED3DFMT_B5G5R5A1_UNORM:
414         case WINED3DFMT_B4G4R4A4_UNORM:
415         case WINED3DFMT_B4G4R4X4_UNORM:
416         case WINED3DFMT_B2G3R3_UNORM:
417         case WINED3DFMT_B2G3R3A8_UNORM:
418         case WINED3DFMT_R10G10B10A2_UNORM:
419         case WINED3DFMT_R8G8B8A8_UNORM:
420         case WINED3DFMT_R8G8B8X8_UNORM:
421         case WINED3DFMT_B10G10R10A2_UNORM:
422         case WINED3DFMT_B5G6R5_UNORM:
423         case WINED3DFMT_R16G16B16A16_UNORM:
424             usage = 0;
425             b_info->bmiHeader.biCompression = BI_BITFIELDS;
426             masks[0] = format->red_mask;
427             masks[1] = format->green_mask;
428             masks[2] = format->blue_mask;
429             break;
430
431         default:
432             /* Don't know palette */
433             b_info->bmiHeader.biCompression = BI_RGB;
434             usage = 0;
435             break;
436     }
437
438     if (!(dc = GetDC(0)))
439     {
440         HeapFree(GetProcessHeap(), 0, b_info);
441         return HRESULT_FROM_WIN32(GetLastError());
442     }
443
444     TRACE("Creating a DIB section with size %dx%dx%d, size=%d.\n",
445             b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight,
446             b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
447     surface->dib.DIBsection = CreateDIBSection(dc, b_info, usage, &surface->dib.bitmap_data, 0, 0);
448     ReleaseDC(0, dc);
449
450     if (!surface->dib.DIBsection)
451     {
452         ERR("Failed to create DIB section.\n");
453         HeapFree(GetProcessHeap(), 0, b_info);
454         return HRESULT_FROM_WIN32(GetLastError());
455     }
456
457     TRACE("DIBSection at %p.\n", surface->dib.bitmap_data);
458     /* Copy the existing surface to the dib section. */
459     if (surface->resource.allocatedMemory)
460     {
461         memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory,
462                 surface->resource.height * IWineD3DSurface_GetPitch((IWineD3DSurface *)surface));
463     }
464     else
465     {
466         /* This is to make maps read the GL texture although memory is allocated. */
467         surface->flags &= ~SFLAG_INSYSMEM;
468     }
469     surface->dib.bitmap_size = b_info->bmiHeader.biSizeImage;
470
471     HeapFree(GetProcessHeap(), 0, b_info);
472
473     /* Now allocate a DC. */
474     surface->hDC = CreateCompatibleDC(0);
475     surface->dib.holdbitmap = SelectObject(surface->hDC, surface->dib.DIBsection);
476     TRACE("Using wined3d palette %p.\n", surface->palette);
477     SelectPalette(surface->hDC, surface->palette ? surface->palette->hpal : 0, FALSE);
478
479     surface->flags |= SFLAG_DIBSECTION;
480
481     HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
482     surface->resource.heapMemory = NULL;
483
484     return WINED3D_OK;
485 }
486
487
488 static HRESULT surface_private_setup(struct IWineD3DSurfaceImpl *surface)
489 {
490     /* TODO: Check against the maximum texture sizes supported by the video card. */
491     const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
492     unsigned int pow2Width, pow2Height;
493
494     TRACE("surface %p.\n", surface);
495
496     surface->texture_name = 0;
497     surface->texture_target = GL_TEXTURE_2D;
498
499     /* Non-power2 support */
500     if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
501     {
502         pow2Width = surface->resource.width;
503         pow2Height = surface->resource.height;
504     }
505     else
506     {
507         /* Find the nearest pow2 match */
508         pow2Width = pow2Height = 1;
509         while (pow2Width < surface->resource.width)
510             pow2Width <<= 1;
511         while (pow2Height < surface->resource.height)
512             pow2Height <<= 1;
513     }
514     surface->pow2Width = pow2Width;
515     surface->pow2Height = pow2Height;
516
517     if (pow2Width > surface->resource.width || pow2Height > surface->resource.height)
518     {
519         /* TODO: Add support for non power two compressed textures. */
520         if (surface->resource.format->flags & WINED3DFMT_FLAG_COMPRESSED)
521         {
522             FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
523                   surface, surface->resource.width, surface->resource.height);
524             return WINED3DERR_NOTAVAILABLE;
525         }
526     }
527
528     if (pow2Width != surface->resource.width
529             || pow2Height != surface->resource.height)
530     {
531         surface->flags |= SFLAG_NONPOW2;
532     }
533
534     if ((surface->pow2Width > gl_info->limits.texture_size || surface->pow2Height > gl_info->limits.texture_size)
535             && !(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
536     {
537         /* One of three options:
538          * 1: Do the same as we do with NPOT and scale the texture, (any
539          *    texture ops would require the texture to be scaled which is
540          *    potentially slow)
541          * 2: Set the texture to the maximum size (bad idea).
542          * 3: WARN and return WINED3DERR_NOTAVAILABLE;
543          * 4: Create the surface, but allow it to be used only for DirectDraw
544          *    Blts. Some apps (e.g. Swat 3) create textures with a Height of
545          *    16 and a Width > 3000 and blt 16x16 letter areas from them to
546          *    the render target. */
547         if (surface->resource.pool == WINED3DPOOL_DEFAULT || surface->resource.pool == WINED3DPOOL_MANAGED)
548         {
549             WARN("Unable to allocate a surface which exceeds the maximum OpenGL texture size.\n");
550             return WINED3DERR_NOTAVAILABLE;
551         }
552
553         /* We should never use this surface in combination with OpenGL! */
554         TRACE("Creating an oversized surface: %ux%u.\n",
555                 surface->pow2Width, surface->pow2Height);
556     }
557     else
558     {
559         /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8
560          * and EXT_PALETTED_TEXTURE is used in combination with texture
561          * uploads (RTL_READTEX/RTL_TEXTEX). The reason is that
562          * EXT_PALETTED_TEXTURE doesn't work in combination with
563          * ARB_TEXTURE_RECTANGLE. */
564         if (surface->flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
565                 && !(surface->resource.format->id == WINED3DFMT_P8_UINT
566                 && gl_info->supported[EXT_PALETTED_TEXTURE]
567                 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
568         {
569             surface->texture_target = GL_TEXTURE_RECTANGLE_ARB;
570             surface->pow2Width = surface->resource.width;
571             surface->pow2Height = surface->resource.height;
572             surface->flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
573         }
574     }
575
576     switch (wined3d_settings.offscreen_rendering_mode)
577     {
578         case ORM_FBO:
579             surface->get_drawable_size = get_drawable_size_fbo;
580             break;
581
582         case ORM_BACKBUFFER:
583             surface->get_drawable_size = get_drawable_size_backbuffer;
584             break;
585
586         default:
587             ERR("Unhandled offscreen rendering mode %#x.\n", wined3d_settings.offscreen_rendering_mode);
588             return WINED3DERR_INVALIDCALL;
589     }
590
591     surface->flags |= SFLAG_INSYSMEM;
592
593     return WINED3D_OK;
594 }
595
596 static void surface_realize_palette(IWineD3DSurfaceImpl *surface)
597 {
598     struct wined3d_palette *palette = surface->palette;
599
600     TRACE("surface %p.\n", surface);
601
602     if (!palette) return;
603
604     if (surface->resource.format->id == WINED3DFMT_P8_UINT
605             || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
606     {
607         if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
608         {
609             /* Make sure the texture is up to date. This call doesn't do
610              * anything if the texture is already up to date. */
611             surface_load_location(surface, SFLAG_INTEXTURE, NULL);
612
613             /* We want to force a palette refresh, so mark the drawable as not being up to date */
614             if (!surface_is_offscreen(surface))
615                 surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
616         }
617         else
618         {
619             if (!(surface->flags & SFLAG_INSYSMEM))
620             {
621                 TRACE("Palette changed with surface that does not have an up to date system memory copy.\n");
622                 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
623             }
624             surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
625         }
626     }
627
628     if (surface->flags & SFLAG_DIBSECTION)
629     {
630         RGBQUAD col[256];
631         unsigned int i;
632
633         TRACE("Updating the DC's palette.\n");
634
635         for (i = 0; i < 256; ++i)
636         {
637             col[i].rgbRed   = palette->palents[i].peRed;
638             col[i].rgbGreen = palette->palents[i].peGreen;
639             col[i].rgbBlue  = palette->palents[i].peBlue;
640             col[i].rgbReserved = 0;
641         }
642         SetDIBColorTable(surface->hDC, 0, 256, col);
643     }
644
645     /* Propagate the changes to the drawable when we have a palette. */
646     if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
647         surface_load_location(surface, SFLAG_INDRAWABLE, NULL);
648 }
649
650 static HRESULT surface_draw_overlay(IWineD3DSurfaceImpl *surface)
651 {
652     HRESULT hr;
653
654     /* If there's no destination surface there is nothing to do. */
655     if (!surface->overlay_dest)
656         return WINED3D_OK;
657
658     /* Blt calls ModifyLocation on the dest surface, which in turn calls
659      * DrawOverlay to update the overlay. Prevent an endless recursion. */
660     if (surface->overlay_dest->flags & SFLAG_INOVERLAYDRAW)
661         return WINED3D_OK;
662
663     surface->overlay_dest->flags |= SFLAG_INOVERLAYDRAW;
664     hr = IWineD3DSurface_Blt((IWineD3DSurface *)surface->overlay_dest,
665             &surface->overlay_destrect, (IWineD3DSurface *)surface, &surface->overlay_srcrect,
666             WINEDDBLT_WAIT, NULL, WINED3DTEXF_LINEAR);
667     surface->overlay_dest->flags &= ~SFLAG_INOVERLAYDRAW;
668
669     return hr;
670 }
671
672 /* Context activation is done by the caller. */
673 static void surface_remove_pbo(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info)
674 {
675     if (!surface->resource.heapMemory)
676     {
677         surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), 0, surface->resource.size + RESOURCE_ALIGNMENT);
678         surface->resource.allocatedMemory = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
679                 + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
680     }
681
682     ENTER_GL();
683     GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
684     checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, surface->pbo)");
685     GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0,
686             surface->resource.size, surface->resource.allocatedMemory));
687     checkGLcall("glGetBufferSubDataARB");
688     GL_EXTCALL(glDeleteBuffersARB(1, &surface->pbo));
689     checkGLcall("glDeleteBuffersARB");
690     LEAVE_GL();
691
692     surface->pbo = 0;
693     surface->flags &= ~SFLAG_PBO;
694 }
695
696 /* Do not call while under the GL lock. */
697 static void surface_unload(struct wined3d_resource *resource)
698 {
699     IWineD3DSurfaceImpl *surface = surface_from_resource(resource);
700     IWineD3DDeviceImpl *device = resource->device;
701     const struct wined3d_gl_info *gl_info;
702     renderbuffer_entry_t *entry, *entry2;
703     struct wined3d_context *context;
704
705     TRACE("surface %p.\n", surface);
706
707     if (resource->pool == WINED3DPOOL_DEFAULT)
708     {
709         /* Default pool resources are supposed to be destroyed before Reset is called.
710          * Implicit resources stay however. So this means we have an implicit render target
711          * or depth stencil. The content may be destroyed, but we still have to tear down
712          * opengl resources, so we cannot leave early.
713          *
714          * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
715          * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
716          * or the depth stencil into an FBO the texture or render buffer will be removed
717          * and all flags get lost
718          */
719         surface_init_sysmem(surface);
720     }
721     else
722     {
723         /* Load the surface into system memory */
724         surface_load_location(surface, SFLAG_INSYSMEM, NULL);
725         surface_modify_location(surface, SFLAG_INDRAWABLE, FALSE);
726     }
727     surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
728     surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
729     surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
730
731     context = context_acquire(device, NULL);
732     gl_info = context->gl_info;
733
734     /* Destroy PBOs, but load them into real sysmem before */
735     if (surface->flags & SFLAG_PBO)
736         surface_remove_pbo(surface, gl_info);
737
738     /* Destroy fbo render buffers. This is needed for implicit render targets, for
739      * all application-created targets the application has to release the surface
740      * before calling _Reset
741      */
742     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &surface->renderbuffers, renderbuffer_entry_t, entry)
743     {
744         ENTER_GL();
745         gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
746         LEAVE_GL();
747         list_remove(&entry->entry);
748         HeapFree(GetProcessHeap(), 0, entry);
749     }
750     list_init(&surface->renderbuffers);
751     surface->current_renderbuffer = NULL;
752
753     /* If we're in a texture, the texture name belongs to the texture.
754      * Otherwise, destroy it. */
755     if (surface->container.type != WINED3D_CONTAINER_TEXTURE)
756     {
757         ENTER_GL();
758         glDeleteTextures(1, &surface->texture_name);
759         surface->texture_name = 0;
760         glDeleteTextures(1, &surface->texture_name_srgb);
761         surface->texture_name_srgb = 0;
762         LEAVE_GL();
763     }
764
765     context_release(context);
766
767     resource_unload(resource);
768 }
769
770 static const struct wined3d_resource_ops surface_resource_ops =
771 {
772     surface_unload,
773 };
774
775 static const struct wined3d_surface_ops surface_ops =
776 {
777     surface_private_setup,
778     surface_realize_palette,
779     surface_draw_overlay,
780 };
781
782 /*****************************************************************************
783  * Initializes the GDI surface, aka creates the DIB section we render to
784  * The DIB section creation is done by calling GetDC, which will create the
785  * section and releasing the dc to allow the app to use it. The dib section
786  * will stay until the surface is released
787  *
788  * GDI surfaces do not need to be a power of 2 in size, so the pow2 sizes
789  * are set to the real sizes to save memory. The NONPOW2 flag is unset to
790  * avoid confusion in the shared surface code.
791  *
792  * Returns:
793  *  WINED3D_OK on success
794  *  The return values of called methods on failure
795  *
796  *****************************************************************************/
797 static HRESULT gdi_surface_private_setup(IWineD3DSurfaceImpl *surface)
798 {
799     HRESULT hr;
800
801     TRACE("surface %p.\n", surface);
802
803     if (surface->resource.usage & WINED3DUSAGE_OVERLAY)
804     {
805         ERR("Overlays not yet supported by GDI surfaces.\n");
806         return WINED3DERR_INVALIDCALL;
807     }
808
809     /* Sysmem textures have memory already allocated - release it,
810      * this avoids an unnecessary memcpy. */
811     hr = surface_create_dib_section(surface);
812     if (SUCCEEDED(hr))
813     {
814         HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
815         surface->resource.heapMemory = NULL;
816         surface->resource.allocatedMemory = surface->dib.bitmap_data;
817     }
818
819     /* We don't mind the nonpow2 stuff in GDI. */
820     surface->pow2Width = surface->resource.width;
821     surface->pow2Height = surface->resource.height;
822
823     return WINED3D_OK;
824 }
825
826 static void surface_gdi_cleanup(IWineD3DSurfaceImpl *surface)
827 {
828     TRACE("surface %p.\n", surface);
829
830     if (surface->flags & SFLAG_DIBSECTION)
831     {
832         /* Release the DC. */
833         SelectObject(surface->hDC, surface->dib.holdbitmap);
834         DeleteDC(surface->hDC);
835         /* Release the DIB section. */
836         DeleteObject(surface->dib.DIBsection);
837         surface->dib.bitmap_data = NULL;
838         surface->resource.allocatedMemory = NULL;
839     }
840
841     if (surface->flags & SFLAG_USERPTR)
842         IWineD3DSurface_SetMem((IWineD3DSurface *)surface, NULL);
843     if (surface->overlay_dest)
844         list_remove(&surface->overlay_entry);
845
846     HeapFree(GetProcessHeap(), 0, surface->palette9);
847
848     resource_cleanup(&surface->resource);
849 }
850
851 static void gdi_surface_realize_palette(IWineD3DSurfaceImpl *surface)
852 {
853     struct wined3d_palette *palette = surface->palette;
854
855     TRACE("surface %p.\n", surface);
856
857     if (!palette) return;
858
859     if (surface->flags & SFLAG_DIBSECTION)
860     {
861         RGBQUAD col[256];
862         unsigned int i;
863
864         TRACE("Updating the DC's palette.\n");
865
866         for (i = 0; i < 256; ++i)
867         {
868             col[i].rgbRed = palette->palents[i].peRed;
869             col[i].rgbGreen = palette->palents[i].peGreen;
870             col[i].rgbBlue = palette->palents[i].peBlue;
871             col[i].rgbReserved = 0;
872         }
873         SetDIBColorTable(surface->hDC, 0, 256, col);
874     }
875
876     /* Update the image because of the palette change. Some games like e.g.
877      * Red Alert call SetEntries a lot to implement fading. */
878     /* Tell the swapchain to update the screen. */
879     if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
880     {
881         struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
882         if (surface == swapchain->front_buffer)
883         {
884             x11_copy_to_screen(swapchain, NULL);
885         }
886     }
887 }
888
889 static HRESULT gdi_surface_draw_overlay(IWineD3DSurfaceImpl *surface)
890 {
891     FIXME("GDI surfaces can't draw overlays yet.\n");
892     return E_FAIL;
893 }
894
895 static const struct wined3d_surface_ops gdi_surface_ops =
896 {
897     gdi_surface_private_setup,
898     gdi_surface_realize_palette,
899     gdi_surface_draw_overlay,
900 };
901
902 static void surface_force_reload(IWineD3DSurfaceImpl *surface)
903 {
904     surface->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
905 }
906
907 void surface_set_texture_name(IWineD3DSurfaceImpl *surface, GLuint new_name, BOOL srgb)
908 {
909     GLuint *name;
910     DWORD flag;
911
912     TRACE("surface %p, new_name %u, srgb %#x.\n", surface, new_name, srgb);
913
914     if(srgb)
915     {
916         name = &surface->texture_name_srgb;
917         flag = SFLAG_INSRGBTEX;
918     }
919     else
920     {
921         name = &surface->texture_name;
922         flag = SFLAG_INTEXTURE;
923     }
924
925     if (!*name && new_name)
926     {
927         /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
928          * surface has no texture name yet. See if we can get rid of this. */
929         if (surface->flags & flag)
930             ERR("Surface has %s set, but no texture name.\n", debug_surflocation(flag));
931         surface_modify_location(surface, flag, FALSE);
932     }
933
934     *name = new_name;
935     surface_force_reload(surface);
936 }
937
938 void surface_set_texture_target(IWineD3DSurfaceImpl *surface, GLenum target)
939 {
940     TRACE("surface %p, target %#x.\n", surface, target);
941
942     if (surface->texture_target != target)
943     {
944         if (target == GL_TEXTURE_RECTANGLE_ARB)
945         {
946             surface->flags &= ~SFLAG_NORMCOORD;
947         }
948         else if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
949         {
950             surface->flags |= SFLAG_NORMCOORD;
951         }
952     }
953     surface->texture_target = target;
954     surface_force_reload(surface);
955 }
956
957 /* Context activation is done by the caller. */
958 void surface_bind(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info, BOOL srgb)
959 {
960     TRACE("surface %p, gl_info %p, srgb %#x.\n", surface, gl_info, srgb);
961
962     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
963     {
964         struct wined3d_texture *texture = surface->container.u.texture;
965
966         TRACE("Passing to container (%p).\n", texture);
967         texture->texture_ops->texture_bind(texture, gl_info, srgb);
968     }
969     else
970     {
971         if (surface->texture_level)
972         {
973             ERR("Standalone surface %p is non-zero texture level %u.\n",
974                     surface, surface->texture_level);
975         }
976
977         if (srgb)
978             ERR("Trying to bind standalone surface %p as sRGB.\n", surface);
979
980         ENTER_GL();
981
982         if (!surface->texture_name)
983         {
984             glGenTextures(1, &surface->texture_name);
985             checkGLcall("glGenTextures");
986
987             TRACE("Surface %p given name %u.\n", surface, surface->texture_name);
988
989             glBindTexture(surface->texture_target, surface->texture_name);
990             checkGLcall("glBindTexture");
991             glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
992             glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
993             glTexParameteri(surface->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
994             glTexParameteri(surface->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
995             glTexParameteri(surface->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
996             checkGLcall("glTexParameteri");
997         }
998         else
999         {
1000             glBindTexture(surface->texture_target, surface->texture_name);
1001             checkGLcall("glBindTexture");
1002         }
1003
1004         LEAVE_GL();
1005     }
1006 }
1007
1008 /* Context activation is done by the caller. */
1009 static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *surface,
1010         const struct wined3d_gl_info *gl_info, BOOL srgb)
1011 {
1012     IWineD3DDeviceImpl *device = surface->resource.device;
1013     DWORD active_sampler;
1014
1015     /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
1016      * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
1017      * gl states. The current texture unit should always be a valid one.
1018      *
1019      * To be more specific, this is tricky because we can implicitly be called
1020      * from sampler() in state.c. This means we can't touch anything other than
1021      * whatever happens to be the currently active texture, or we would risk
1022      * marking already applied sampler states dirty again.
1023      *
1024      * TODO: Track the current active texture per GL context instead of using glGet
1025      */
1026     GLint active_texture;
1027     ENTER_GL();
1028     glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
1029     LEAVE_GL();
1030     active_sampler = device->rev_tex_unit_map[active_texture - GL_TEXTURE0_ARB];
1031
1032     if (active_sampler != WINED3D_UNMAPPED_STAGE)
1033     {
1034         IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(active_sampler));
1035     }
1036     surface_bind(surface, gl_info, srgb);
1037 }
1038
1039 /* This function checks if the primary render target uses the 8bit paletted format. */
1040 static BOOL primary_render_target_is_p8(IWineD3DDeviceImpl *device)
1041 {
1042     if (device->render_targets && device->render_targets[0])
1043     {
1044         IWineD3DSurfaceImpl *render_target = device->render_targets[0];
1045         if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
1046                 && (render_target->resource.format->id == WINED3DFMT_P8_UINT))
1047             return TRUE;
1048     }
1049     return FALSE;
1050 }
1051
1052 /* This call just downloads data, the caller is responsible for binding the
1053  * correct texture. */
1054 /* Context activation is done by the caller. */
1055 static void surface_download_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info)
1056 {
1057     const struct wined3d_format *format = This->resource.format;
1058
1059     /* Only support read back of converted P8 surfaces */
1060     if (This->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
1061     {
1062         FIXME("Readback conversion not supported for format %s.\n", debug_d3dformat(format->id));
1063         return;
1064     }
1065
1066     ENTER_GL();
1067
1068     if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
1069     {
1070         TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
1071                 This, This->texture_level, format->glFormat, format->glType,
1072                 This->resource.allocatedMemory);
1073
1074         if (This->flags & SFLAG_PBO)
1075         {
1076             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
1077             checkGLcall("glBindBufferARB");
1078             GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target, This->texture_level, NULL));
1079             checkGLcall("glGetCompressedTexImageARB");
1080             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
1081             checkGLcall("glBindBufferARB");
1082         }
1083         else
1084         {
1085             GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target,
1086                     This->texture_level, This->resource.allocatedMemory));
1087             checkGLcall("glGetCompressedTexImageARB");
1088         }
1089
1090         LEAVE_GL();
1091     } else {
1092         void *mem;
1093         GLenum gl_format = format->glFormat;
1094         GLenum gl_type = format->glType;
1095         int src_pitch = 0;
1096         int dst_pitch = 0;
1097
1098         /* In case of P8 the index is stored in the alpha component if the primary render target uses P8 */
1099         if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(This->resource.device))
1100         {
1101             gl_format = GL_ALPHA;
1102             gl_type = GL_UNSIGNED_BYTE;
1103         }
1104
1105         if (This->flags & SFLAG_NONPOW2)
1106         {
1107             unsigned char alignment = This->resource.device->surface_alignment;
1108             src_pitch = format->byte_count * This->pow2Width;
1109             dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
1110             src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
1111             mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
1112         } else {
1113             mem = This->resource.allocatedMemory;
1114         }
1115
1116         TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
1117                 This, This->texture_level, gl_format, gl_type, mem);
1118
1119         if (This->flags & SFLAG_PBO)
1120         {
1121             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
1122             checkGLcall("glBindBufferARB");
1123
1124             glGetTexImage(This->texture_target, This->texture_level, gl_format, gl_type, NULL);
1125             checkGLcall("glGetTexImage");
1126
1127             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
1128             checkGLcall("glBindBufferARB");
1129         } else {
1130             glGetTexImage(This->texture_target, This->texture_level, gl_format, gl_type, mem);
1131             checkGLcall("glGetTexImage");
1132         }
1133         LEAVE_GL();
1134
1135         if (This->flags & SFLAG_NONPOW2)
1136         {
1137             const BYTE *src_data;
1138             BYTE *dst_data;
1139             UINT y;
1140             /*
1141              * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
1142              * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
1143              * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
1144              *
1145              * We're doing this...
1146              *
1147              * instead of boxing the texture :
1148              * |<-texture width ->|  -->pow2width|   /\
1149              * |111111111111111111|              |   |
1150              * |222 Texture 222222| boxed empty  | texture height
1151              * |3333 Data 33333333|              |   |
1152              * |444444444444444444|              |   \/
1153              * -----------------------------------   |
1154              * |     boxed  empty | boxed empty  | pow2height
1155              * |                  |              |   \/
1156              * -----------------------------------
1157              *
1158              *
1159              * we're repacking the data to the expected texture width
1160              *
1161              * |<-texture width ->|  -->pow2width|   /\
1162              * |111111111111111111222222222222222|   |
1163              * |222333333333333333333444444444444| texture height
1164              * |444444                           |   |
1165              * |                                 |   \/
1166              * |                                 |   |
1167              * |            empty                | pow2height
1168              * |                                 |   \/
1169              * -----------------------------------
1170              *
1171              * == is the same as
1172              *
1173              * |<-texture width ->|    /\
1174              * |111111111111111111|
1175              * |222222222222222222|texture height
1176              * |333333333333333333|
1177              * |444444444444444444|    \/
1178              * --------------------
1179              *
1180              * this also means that any references to allocatedMemory should work with the data as if were a
1181              * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
1182              *
1183              * internally the texture is still stored in a boxed format so any references to textureName will
1184              * get a boxed texture with width pow2width and not a texture of width resource.width.
1185              *
1186              * Performance should not be an issue, because applications normally do not lock the surfaces when
1187              * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
1188              * and doesn't have to be re-read.
1189              */
1190             src_data = mem;
1191             dst_data = This->resource.allocatedMemory;
1192             TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
1193             for (y = 1; y < This->resource.height; ++y)
1194             {
1195                 /* skip the first row */
1196                 src_data += src_pitch;
1197                 dst_data += dst_pitch;
1198                 memcpy(dst_data, src_data, dst_pitch);
1199             }
1200
1201             HeapFree(GetProcessHeap(), 0, mem);
1202         }
1203     }
1204
1205     /* Surface has now been downloaded */
1206     This->flags |= SFLAG_INSYSMEM;
1207 }
1208
1209 /* This call just uploads data, the caller is responsible for binding the
1210  * correct texture. */
1211 /* Context activation is done by the caller. */
1212 static void surface_upload_data(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
1213         const struct wined3d_format *format, BOOL srgb, const GLvoid *data)
1214 {
1215     GLsizei width = This->resource.width;
1216     GLsizei height = This->resource.height;
1217     GLenum internal;
1218
1219     if (srgb)
1220     {
1221         internal = format->glGammaInternal;
1222     }
1223     else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(This))
1224     {
1225         internal = format->rtInternal;
1226     }
1227     else
1228     {
1229         internal = format->glInternal;
1230     }
1231
1232     TRACE("This %p, internal %#x, width %d, height %d, format %#x, type %#x, data %p.\n",
1233             This, internal, width, height, format->glFormat, format->glType, data);
1234     TRACE("target %#x, level %u, resource size %u.\n",
1235             This->texture_target, This->texture_level, This->resource.size);
1236
1237     if (format->heightscale != 1.0f && format->heightscale != 0.0f) height *= format->heightscale;
1238
1239     ENTER_GL();
1240
1241     if (This->flags & SFLAG_PBO)
1242     {
1243         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1244         checkGLcall("glBindBufferARB");
1245
1246         TRACE("(%p) pbo: %#x, data: %p.\n", This, This->pbo, data);
1247         data = NULL;
1248     }
1249
1250     if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
1251     {
1252         TRACE("Calling glCompressedTexSubImage2DARB.\n");
1253
1254         GL_EXTCALL(glCompressedTexSubImage2DARB(This->texture_target, This->texture_level,
1255                 0, 0, width, height, internal, This->resource.size, data));
1256         checkGLcall("glCompressedTexSubImage2DARB");
1257     }
1258     else
1259     {
1260         TRACE("Calling glTexSubImage2D.\n");
1261
1262         glTexSubImage2D(This->texture_target, This->texture_level,
1263                 0, 0, width, height, format->glFormat, format->glType, data);
1264         checkGLcall("glTexSubImage2D");
1265     }
1266
1267     if (This->flags & SFLAG_PBO)
1268     {
1269         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1270         checkGLcall("glBindBufferARB");
1271     }
1272
1273     LEAVE_GL();
1274
1275     if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
1276     {
1277         IWineD3DDeviceImpl *device = This->resource.device;
1278         unsigned int i;
1279
1280         for (i = 0; i < device->context_count; ++i)
1281         {
1282             context_surface_update(device->contexts[i], This);
1283         }
1284     }
1285 }
1286
1287 /* This call just allocates the texture, the caller is responsible for binding
1288  * the correct texture. */
1289 /* Context activation is done by the caller. */
1290 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
1291         const struct wined3d_format *format, BOOL srgb)
1292 {
1293     BOOL enable_client_storage = FALSE;
1294     GLsizei width = This->pow2Width;
1295     GLsizei height = This->pow2Height;
1296     const BYTE *mem = NULL;
1297     GLenum internal;
1298
1299     if (srgb)
1300     {
1301         internal = format->glGammaInternal;
1302     }
1303     else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(This))
1304     {
1305         internal = format->rtInternal;
1306     }
1307     else
1308     {
1309         internal = format->glInternal;
1310     }
1311
1312     if (format->heightscale != 1.0f && format->heightscale != 0.0f) height *= format->heightscale;
1313
1314     TRACE("(%p) : Creating surface (target %#x)  level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n",
1315             This, This->texture_target, This->texture_level, debug_d3dformat(format->id),
1316             internal, width, height, format->glFormat, format->glType);
1317
1318     ENTER_GL();
1319
1320     if (gl_info->supported[APPLE_CLIENT_STORAGE])
1321     {
1322         if (This->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
1323                 || !This->resource.allocatedMemory)
1324         {
1325             /* In some cases we want to disable client storage.
1326              * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
1327              * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
1328              * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
1329              * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
1330              */
1331             glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1332             checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1333             This->flags &= ~SFLAG_CLIENT;
1334             enable_client_storage = TRUE;
1335         }
1336         else
1337         {
1338             This->flags |= SFLAG_CLIENT;
1339
1340             /* Point opengl to our allocated texture memory. Do not use resource.allocatedMemory here because
1341              * it might point into a pbo. Instead use heapMemory, but get the alignment right.
1342              */
1343             mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1344         }
1345     }
1346
1347     if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
1348     {
1349         GL_EXTCALL(glCompressedTexImage2DARB(This->texture_target, This->texture_level,
1350                 internal, width, height, 0, This->resource.size, mem));
1351         checkGLcall("glCompressedTexImage2DARB");
1352     }
1353     else
1354     {
1355         glTexImage2D(This->texture_target, This->texture_level,
1356                 internal, width, height, 0, format->glFormat, format->glType, mem);
1357         checkGLcall("glTexImage2D");
1358     }
1359
1360     if(enable_client_storage) {
1361         glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1362         checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1363     }
1364     LEAVE_GL();
1365 }
1366
1367 /* In D3D the depth stencil dimensions have to be greater than or equal to the
1368  * render target dimensions. With FBOs, the dimensions have to be an exact match. */
1369 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
1370 /* GL locking is done by the caller */
1371 void surface_set_compatible_renderbuffer(IWineD3DSurfaceImpl *surface, IWineD3DSurfaceImpl *rt)
1372 {
1373     const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
1374     renderbuffer_entry_t *entry;
1375     GLuint renderbuffer = 0;
1376     unsigned int src_width, src_height;
1377     unsigned int width, height;
1378
1379     if (rt && rt->resource.format->id != WINED3DFMT_NULL)
1380     {
1381         width = rt->pow2Width;
1382         height = rt->pow2Height;
1383     }
1384     else
1385     {
1386         width = surface->pow2Width;
1387         height = surface->pow2Height;
1388     }
1389
1390     src_width = surface->pow2Width;
1391     src_height = surface->pow2Height;
1392
1393     /* A depth stencil smaller than the render target is not valid */
1394     if (width > src_width || height > src_height) return;
1395
1396     /* Remove any renderbuffer set if the sizes match */
1397     if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
1398             || (width == src_width && height == src_height))
1399     {
1400         surface->current_renderbuffer = NULL;
1401         return;
1402     }
1403
1404     /* Look if we've already got a renderbuffer of the correct dimensions */
1405     LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, renderbuffer_entry_t, entry)
1406     {
1407         if (entry->width == width && entry->height == height)
1408         {
1409             renderbuffer = entry->id;
1410             surface->current_renderbuffer = entry;
1411             break;
1412         }
1413     }
1414
1415     if (!renderbuffer)
1416     {
1417         gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
1418         gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
1419         gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
1420                 surface->resource.format->glInternal, width, height);
1421
1422         entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
1423         entry->width = width;
1424         entry->height = height;
1425         entry->id = renderbuffer;
1426         list_add_head(&surface->renderbuffers, &entry->entry);
1427
1428         surface->current_renderbuffer = entry;
1429     }
1430
1431     checkGLcall("set_compatible_renderbuffer");
1432 }
1433
1434 GLenum surface_get_gl_buffer(IWineD3DSurfaceImpl *surface)
1435 {
1436     struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
1437
1438     TRACE("surface %p.\n", surface);
1439
1440     if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
1441     {
1442         ERR("Surface %p is not on a swapchain.\n", surface);
1443         return GL_NONE;
1444     }
1445
1446     if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
1447     {
1448         if (swapchain->render_to_fbo)
1449         {
1450             TRACE("Returning GL_COLOR_ATTACHMENT0\n");
1451             return GL_COLOR_ATTACHMENT0;
1452         }
1453         TRACE("Returning GL_BACK\n");
1454         return GL_BACK;
1455     }
1456     else if (surface == swapchain->front_buffer)
1457     {
1458         TRACE("Returning GL_FRONT\n");
1459         return GL_FRONT;
1460     }
1461
1462     FIXME("Higher back buffer, returning GL_BACK\n");
1463     return GL_BACK;
1464 }
1465
1466 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
1467 void surface_add_dirty_rect(IWineD3DSurfaceImpl *surface, const WINED3DBOX *dirty_rect)
1468 {
1469     TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
1470
1471     if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
1472         /* No partial locking for textures yet. */
1473         surface_load_location(surface, SFLAG_INSYSMEM, NULL);
1474
1475     surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1476     if (dirty_rect)
1477     {
1478         surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->Left);
1479         surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->Top);
1480         surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->Right);
1481         surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->Bottom);
1482     }
1483     else
1484     {
1485         surface->dirtyRect.left = 0;
1486         surface->dirtyRect.top = 0;
1487         surface->dirtyRect.right = surface->resource.width;
1488         surface->dirtyRect.bottom = surface->resource.height;
1489     }
1490
1491     /* if the container is a texture then mark it dirty. */
1492     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
1493     {
1494         TRACE("Passing to container.\n");
1495         wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
1496     }
1497 }
1498
1499 static BOOL surface_convert_color_to_float(IWineD3DSurfaceImpl *surface, DWORD color, WINED3DCOLORVALUE *float_color)
1500 {
1501     const struct wined3d_format *format = surface->resource.format;
1502     IWineD3DDeviceImpl *device = surface->resource.device;
1503
1504     switch (format->id)
1505     {
1506         case WINED3DFMT_P8_UINT:
1507             if (surface->palette)
1508             {
1509                 float_color->r = surface->palette->palents[color].peRed / 255.0f;
1510                 float_color->g = surface->palette->palents[color].peGreen / 255.0f;
1511                 float_color->b = surface->palette->palents[color].peBlue / 255.0f;
1512             }
1513             else
1514             {
1515                 float_color->r = 0.0f;
1516                 float_color->g = 0.0f;
1517                 float_color->b = 0.0f;
1518             }
1519             float_color->a = primary_render_target_is_p8(device) ? color / 255.0f : 1.0f;
1520             break;
1521
1522         case WINED3DFMT_B5G6R5_UNORM:
1523             float_color->r = ((color >> 11) & 0x1f) / 31.0f;
1524             float_color->g = ((color >> 5) & 0x3f) / 63.0f;
1525             float_color->b = (color & 0x1f) / 31.0f;
1526             float_color->a = 1.0f;
1527             break;
1528
1529         case WINED3DFMT_B8G8R8_UNORM:
1530         case WINED3DFMT_B8G8R8X8_UNORM:
1531             float_color->r = D3DCOLOR_R(color);
1532             float_color->g = D3DCOLOR_G(color);
1533             float_color->b = D3DCOLOR_B(color);
1534             float_color->a = 1.0f;
1535             break;
1536
1537         case WINED3DFMT_B8G8R8A8_UNORM:
1538             float_color->r = D3DCOLOR_R(color);
1539             float_color->g = D3DCOLOR_G(color);
1540             float_color->b = D3DCOLOR_B(color);
1541             float_color->a = D3DCOLOR_A(color);
1542             break;
1543
1544         default:
1545             ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1546             return FALSE;
1547     }
1548
1549     return TRUE;
1550 }
1551
1552 static BOOL surface_convert_depth_to_float(IWineD3DSurfaceImpl *surface, DWORD depth, float *float_depth)
1553 {
1554     const struct wined3d_format *format = surface->resource.format;
1555
1556     switch (format->id)
1557     {
1558         case WINED3DFMT_S1_UINT_D15_UNORM:
1559             *float_depth = depth / (float)0x00007fff;
1560             break;
1561
1562         case WINED3DFMT_D16_UNORM:
1563             *float_depth = depth / (float)0x0000ffff;
1564             break;
1565
1566         case WINED3DFMT_D24_UNORM_S8_UINT:
1567         case WINED3DFMT_X8D24_UNORM:
1568             *float_depth = depth / (float)0x00ffffff;
1569             break;
1570
1571         case WINED3DFMT_D32_UNORM:
1572             *float_depth = depth / (float)0xffffffff;
1573             break;
1574
1575         default:
1576             ERR("Unhandled conversion from %s to floating point.\n", debug_d3dformat(format->id));
1577             return FALSE;
1578     }
1579
1580     return TRUE;
1581 }
1582
1583 static void surface_evict_sysmem(IWineD3DSurfaceImpl *surface)
1584 {
1585     if (surface->flags & SFLAG_DONOTFREE)
1586         return;
1587
1588     HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
1589     surface->resource.allocatedMemory = NULL;
1590     surface->resource.heapMemory = NULL;
1591     surface_modify_location(surface, SFLAG_INSYSMEM, FALSE);
1592 }
1593
1594 HRESULT surface_load(IWineD3DSurfaceImpl *surface, BOOL srgb)
1595 {
1596     DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
1597
1598     TRACE("surface %p, srgb %#x.\n", surface, srgb);
1599
1600     if (surface->resource.pool == WINED3DPOOL_SCRATCH)
1601     {
1602         ERR("Not supported on scratch surfaces.\n");
1603         return WINED3DERR_INVALIDCALL;
1604     }
1605
1606     if (!(surface->flags & flag))
1607     {
1608         TRACE("Reloading because surface is dirty\n");
1609     }
1610     /* Reload if either the texture and sysmem have different ideas about the
1611      * color key, or the actual key values changed. */
1612     else if (!(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT)
1613             || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
1614             && (surface->glCKey.dwColorSpaceLowValue != surface->SrcBltCKey.dwColorSpaceLowValue
1615             || surface->glCKey.dwColorSpaceHighValue != surface->SrcBltCKey.dwColorSpaceHighValue)))
1616     {
1617         TRACE("Reloading because of color keying\n");
1618         /* To perform the color key conversion we need a sysmem copy of
1619          * the surface. Make sure we have it. */
1620
1621         surface_load_location(surface, SFLAG_INSYSMEM, NULL);
1622         /* Make sure the texture is reloaded because of the color key change,
1623          * this kills performance though :( */
1624         /* TODO: This is not necessarily needed with hw palettized texture support. */
1625         surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
1626     }
1627     else
1628     {
1629         TRACE("surface is already in texture\n");
1630         return WINED3D_OK;
1631     }
1632
1633     /* No partial locking for textures yet. */
1634     surface_load_location(surface, flag, NULL);
1635     surface_evict_sysmem(surface);
1636
1637     return WINED3D_OK;
1638 }
1639
1640 /* See also float_16_to_32() in wined3d_private.h */
1641 static inline unsigned short float_32_to_16(const float *in)
1642 {
1643     int exp = 0;
1644     float tmp = fabs(*in);
1645     unsigned int mantissa;
1646     unsigned short ret;
1647
1648     /* Deal with special numbers */
1649     if (*in == 0.0f)
1650         return 0x0000;
1651     if (isnan(*in))
1652         return 0x7c01;
1653     if (isinf(*in))
1654         return (*in < 0.0f ? 0xfc00 : 0x7c00);
1655
1656     if (tmp < powf(2, 10))
1657     {
1658         do
1659         {
1660             tmp = tmp * 2.0f;
1661             exp--;
1662         } while (tmp < powf(2, 10));
1663     }
1664     else if (tmp >= powf(2, 11))
1665     {
1666         do
1667         {
1668             tmp /= 2.0f;
1669             exp++;
1670         } while (tmp >= powf(2, 11));
1671     }
1672
1673     mantissa = (unsigned int)tmp;
1674     if (tmp - mantissa >= 0.5f)
1675         ++mantissa; /* Round to nearest, away from zero. */
1676
1677     exp += 10;  /* Normalize the mantissa. */
1678     exp += 15;  /* Exponent is encoded with excess 15. */
1679
1680     if (exp > 30) /* too big */
1681     {
1682         ret = 0x7c00; /* INF */
1683     }
1684     else if (exp <= 0)
1685     {
1686         /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
1687         while (exp <= 0)
1688         {
1689             mantissa = mantissa >> 1;
1690             ++exp;
1691         }
1692         ret = mantissa & 0x3ff;
1693     }
1694     else
1695     {
1696         ret = (exp << 10) | (mantissa & 0x3ff);
1697     }
1698
1699     ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
1700     return ret;
1701 }
1702
1703 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_QueryInterface(IWineD3DSurface *iface,
1704         REFIID riid, void **object)
1705 {
1706     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
1707
1708     if (IsEqualGUID(riid, &IID_IWineD3DSurface)
1709             || IsEqualGUID(riid, &IID_IUnknown))
1710     {
1711         IUnknown_AddRef(iface);
1712         *object = iface;
1713         return S_OK;
1714     }
1715
1716     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
1717
1718     *object = NULL;
1719     return E_NOINTERFACE;
1720 }
1721
1722 static ULONG WINAPI IWineD3DBaseSurfaceImpl_AddRef(IWineD3DSurface *iface)
1723 {
1724     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1725     ULONG refcount;
1726
1727     TRACE("Surface %p, container %p of type %#x.\n",
1728             surface, surface->container.u.base, surface->container.type);
1729
1730     switch (surface->container.type)
1731     {
1732         case WINED3D_CONTAINER_TEXTURE:
1733             return wined3d_texture_incref(surface->container.u.texture);
1734
1735         case WINED3D_CONTAINER_SWAPCHAIN:
1736             return wined3d_swapchain_incref(surface->container.u.swapchain);
1737
1738         default:
1739             ERR("Unhandled container type %#x.\n", surface->container.type);
1740         case WINED3D_CONTAINER_NONE:
1741             break;
1742     }
1743
1744     refcount = InterlockedIncrement(&surface->resource.ref);
1745     TRACE("%p increasing refcount to %u.\n", surface, refcount);
1746
1747     return refcount;
1748 }
1749
1750 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPrivateData(IWineD3DSurface *iface,
1751         REFGUID riid, const void *data, DWORD data_size, DWORD flags)
1752 {
1753     return resource_set_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, riid, data, data_size, flags);
1754 }
1755
1756 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPrivateData(IWineD3DSurface *iface,
1757         REFGUID guid, void *data, DWORD *data_size)
1758 {
1759     return resource_get_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, guid, data, data_size);
1760 }
1761
1762 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid)
1763 {
1764     return resource_free_private_data(&((IWineD3DSurfaceImpl *)iface)->resource, refguid);
1765 }
1766
1767 static DWORD WINAPI IWineD3DBaseSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD priority)
1768 {
1769     return resource_set_priority(&((IWineD3DSurfaceImpl *)iface)->resource, priority);
1770 }
1771
1772 static DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPriority(IWineD3DSurface *iface)
1773 {
1774     return resource_get_priority(&((IWineD3DSurfaceImpl *)iface)->resource);
1775 }
1776
1777 static void * WINAPI IWineD3DBaseSurfaceImpl_GetParent(IWineD3DSurface *iface)
1778 {
1779     TRACE("iface %p.\n", iface);
1780
1781     return ((IWineD3DSurfaceImpl *)iface)->resource.parent;
1782 }
1783
1784 static struct wined3d_resource * WINAPI IWineD3DBaseSurfaceImpl_GetResource(IWineD3DSurface *iface)
1785 {
1786     TRACE("iface %p.\n", iface);
1787
1788     return &((IWineD3DSurfaceImpl *)iface)->resource;
1789 }
1790
1791 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD flags)
1792 {
1793     TRACE("iface %p, flags %#x.\n", iface, flags);
1794
1795     switch (flags)
1796     {
1797         case WINEDDGBS_CANBLT:
1798         case WINEDDGBS_ISBLTDONE:
1799             return WINED3D_OK;
1800
1801         default:
1802             return WINED3DERR_INVALIDCALL;
1803     }
1804 }
1805
1806 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD flags)
1807 {
1808     /* XXX: DDERR_INVALIDSURFACETYPE */
1809
1810     TRACE("iface %p, flags %#x.\n", iface, flags);
1811
1812     switch (flags)
1813     {
1814         case WINEDDGFS_CANFLIP:
1815         case WINEDDGFS_ISFLIPDONE:
1816             return WINED3D_OK;
1817
1818         default:
1819             return WINED3DERR_INVALIDCALL;
1820     }
1821 }
1822
1823 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_IsLost(IWineD3DSurface *iface)
1824 {
1825     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1826
1827     TRACE("iface %p.\n", iface);
1828
1829     /* D3D8 and 9 loose full devices, ddraw only surfaces. */
1830     return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
1831 }
1832
1833 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Restore(IWineD3DSurface *iface)
1834 {
1835     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1836
1837     TRACE("iface %p.\n", iface);
1838
1839     /* So far we don't lose anything :) */
1840     surface->flags &= ~SFLAG_LOST;
1841     return WINED3D_OK;
1842 }
1843
1844 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetPalette(IWineD3DSurface *iface, struct wined3d_palette *palette)
1845 {
1846     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1847
1848     TRACE("iface %p, palette %p.\n", iface, palette);
1849
1850     if (surface->palette == palette)
1851     {
1852         TRACE("Nop palette change.\n");
1853         return WINED3D_OK;
1854     }
1855
1856     if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
1857         surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
1858
1859     surface->palette = palette;
1860
1861     if (palette)
1862     {
1863         if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
1864             palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
1865
1866         surface->surface_ops->surface_realize_palette(surface);
1867     }
1868
1869     return WINED3D_OK;
1870 }
1871
1872 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetColorKey(IWineD3DSurface *iface,
1873         DWORD flags, const WINEDDCOLORKEY *color_key)
1874 {
1875     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1876
1877     TRACE("iface %p, flags %#x, color_key %p.\n", iface, flags, color_key);
1878
1879     if (flags & WINEDDCKEY_COLORSPACE)
1880     {
1881         FIXME(" colorkey value not supported (%08x) !\n", flags);
1882         return WINED3DERR_INVALIDCALL;
1883     }
1884
1885     /* Dirtify the surface, but only if a key was changed. */
1886     if (color_key)
1887     {
1888         switch (flags & ~WINEDDCKEY_COLORSPACE)
1889         {
1890             case WINEDDCKEY_DESTBLT:
1891                 surface->DestBltCKey = *color_key;
1892                 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
1893                 break;
1894
1895             case WINEDDCKEY_DESTOVERLAY:
1896                 surface->DestOverlayCKey = *color_key;
1897                 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
1898                 break;
1899
1900             case WINEDDCKEY_SRCOVERLAY:
1901                 surface->SrcOverlayCKey = *color_key;
1902                 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
1903                 break;
1904
1905             case WINEDDCKEY_SRCBLT:
1906                 surface->SrcBltCKey = *color_key;
1907                 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
1908                 break;
1909         }
1910     }
1911     else
1912     {
1913         switch (flags & ~WINEDDCKEY_COLORSPACE)
1914         {
1915             case WINEDDCKEY_DESTBLT:
1916                 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
1917                 break;
1918
1919             case WINEDDCKEY_DESTOVERLAY:
1920                 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
1921                 break;
1922
1923             case WINEDDCKEY_SRCOVERLAY:
1924                 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
1925                 break;
1926
1927             case WINEDDCKEY_SRCBLT:
1928                 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
1929                 break;
1930         }
1931     }
1932
1933     return WINED3D_OK;
1934 }
1935
1936 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetPalette(IWineD3DSurface *iface, struct wined3d_palette **palette)
1937 {
1938     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) iface;
1939
1940     TRACE("iface %p, palette %p.\n", iface, palette);
1941
1942     *palette = surface->palette;
1943
1944     return WINED3D_OK;
1945 }
1946
1947 static DWORD WINAPI IWineD3DBaseSurfaceImpl_GetPitch(IWineD3DSurface *iface)
1948 {
1949     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1950     const struct wined3d_format *format = surface->resource.format;
1951     DWORD pitch;
1952
1953     TRACE("iface %p.\n", iface);
1954
1955     if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
1956     {
1957         /* Since compressed formats are block based, pitch means the amount of
1958          * bytes to the next row of block rather than the next row of pixels. */
1959         UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
1960         pitch = row_block_count * format->block_byte_count;
1961     }
1962     else
1963     {
1964         unsigned char alignment = surface->resource.device->surface_alignment;
1965         pitch = surface->resource.format->byte_count * surface->resource.width;  /* Bytes / row */
1966         pitch = (pitch + alignment - 1) & ~(alignment - 1);
1967     }
1968
1969     TRACE("Returning %u.\n", pitch);
1970
1971     return pitch;
1972 }
1973
1974 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG x, LONG y)
1975 {
1976     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
1977     LONG w, h;
1978
1979     TRACE("iface %p, x %d, y %d.\n", iface, x, y);
1980
1981     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
1982     {
1983         WARN("Not an overlay surface.\n");
1984         return WINEDDERR_NOTAOVERLAYSURFACE;
1985     }
1986
1987     w = surface->overlay_destrect.right - surface->overlay_destrect.left;
1988     h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
1989     surface->overlay_destrect.left = x;
1990     surface->overlay_destrect.top = y;
1991     surface->overlay_destrect.right = x + w;
1992     surface->overlay_destrect.bottom = y + h;
1993
1994     surface->surface_ops->surface_draw_overlay(surface);
1995
1996     return WINED3D_OK;
1997 }
1998
1999 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *x, LONG *y)
2000 {
2001     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2002
2003     TRACE("iface %p, x %p, y %p.\n", iface, x, y);
2004
2005     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2006     {
2007         TRACE("Not an overlay surface.\n");
2008         return WINEDDERR_NOTAOVERLAYSURFACE;
2009     }
2010
2011     if (!surface->overlay_dest)
2012     {
2013         TRACE("Overlay not visible.\n");
2014         *x = 0;
2015         *y = 0;
2016         return WINEDDERR_OVERLAYNOTVISIBLE;
2017     }
2018
2019     *x = surface->overlay_destrect.left;
2020     *y = surface->overlay_destrect.top;
2021
2022     TRACE("Returning position %d, %d.\n", *x, *y);
2023
2024     return WINED3D_OK;
2025 }
2026
2027 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface,
2028         DWORD flags, IWineD3DSurface *ref)
2029 {
2030     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2031
2032     FIXME("iface %p, flags %#x, ref %p stub!\n", iface, flags, ref);
2033
2034     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2035     {
2036         TRACE("Not an overlay surface.\n");
2037         return WINEDDERR_NOTAOVERLAYSURFACE;
2038     }
2039
2040     return WINED3D_OK;
2041 }
2042
2043 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, const RECT *src_rect,
2044         IWineD3DSurface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
2045 {
2046     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2047     IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *)dst_surface;
2048
2049     TRACE("iface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
2050             iface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
2051
2052     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
2053     {
2054         WARN("Not an overlay surface.\n");
2055         return WINEDDERR_NOTAOVERLAYSURFACE;
2056     }
2057     else if (!dst_surface)
2058     {
2059         WARN("Dest surface is NULL.\n");
2060         return WINED3DERR_INVALIDCALL;
2061     }
2062
2063     if (src_rect)
2064     {
2065         surface->overlay_srcrect = *src_rect;
2066     }
2067     else
2068     {
2069         surface->overlay_srcrect.left = 0;
2070         surface->overlay_srcrect.top = 0;
2071         surface->overlay_srcrect.right = surface->resource.width;
2072         surface->overlay_srcrect.bottom = surface->resource.height;
2073     }
2074
2075     if (dst_rect)
2076     {
2077         surface->overlay_destrect = *dst_rect;
2078     }
2079     else
2080     {
2081         surface->overlay_destrect.left = 0;
2082         surface->overlay_destrect.top = 0;
2083         surface->overlay_destrect.right = Dst ? Dst->resource.width : 0;
2084         surface->overlay_destrect.bottom = Dst ? Dst->resource.height : 0;
2085     }
2086
2087     if (surface->overlay_dest && (surface->overlay_dest != Dst || flags & WINEDDOVER_HIDE))
2088     {
2089         list_remove(&surface->overlay_entry);
2090     }
2091
2092     if (flags & WINEDDOVER_SHOW)
2093     {
2094         if (surface->overlay_dest != Dst)
2095         {
2096             surface->overlay_dest = Dst;
2097             list_add_tail(&Dst->overlays, &surface->overlay_entry);
2098         }
2099     }
2100     else if (flags & WINEDDOVER_HIDE)
2101     {
2102         /* tests show that the rectangles are erased on hide */
2103         surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
2104         surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
2105         surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
2106         surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
2107         surface->overlay_dest = NULL;
2108     }
2109
2110     surface->surface_ops->surface_draw_overlay(surface);
2111
2112     return WINED3D_OK;
2113 }
2114
2115 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetClipper(IWineD3DSurface *iface, struct wined3d_clipper *clipper)
2116 {
2117     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2118
2119     TRACE("iface %p, clipper %p.\n", iface, clipper);
2120
2121     surface->clipper = clipper;
2122
2123     return WINED3D_OK;
2124 }
2125
2126 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_GetClipper(IWineD3DSurface *iface, struct wined3d_clipper **clipper)
2127 {
2128     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2129
2130     TRACE("iface %p, clipper %p.\n", iface, clipper);
2131
2132     *clipper = surface->clipper;
2133     if (*clipper)
2134         wined3d_clipper_incref(*clipper);
2135
2136     return WINED3D_OK;
2137 }
2138
2139 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format_id)
2140 {
2141     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
2142     const struct wined3d_format *format = wined3d_get_format(&surface->resource.device->adapter->gl_info, format_id);
2143
2144     TRACE("iface %p, format %s.\n", iface, debug_d3dformat(format_id));
2145
2146     if (surface->resource.format->id != WINED3DFMT_UNKNOWN)
2147     {
2148         FIXME("The format of the surface must be WINED3DFORMAT_UNKNOWN.\n");
2149         return WINED3DERR_INVALIDCALL;
2150     }
2151
2152     surface->resource.size = wined3d_format_calculate_size(format, surface->resource.device->surface_alignment,
2153             surface->pow2Width, surface->pow2Height);
2154     surface->flags |= (WINED3DFMT_D16_LOCKABLE == format_id) ? SFLAG_LOCKABLE : 0;
2155     surface->resource.format = format;
2156
2157     TRACE("size %u, byte_count %u\n", surface->resource.size, format->byte_count);
2158
2159     return WINED3D_OK;
2160 }
2161
2162 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
2163         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2164 {
2165     unsigned short *dst_s;
2166     const float *src_f;
2167     unsigned int x, y;
2168
2169     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2170
2171     for (y = 0; y < h; ++y)
2172     {
2173         src_f = (const float *)(src + y * pitch_in);
2174         dst_s = (unsigned short *) (dst + y * pitch_out);
2175         for (x = 0; x < w; ++x)
2176         {
2177             dst_s[x] = float_32_to_16(src_f + x);
2178         }
2179     }
2180 }
2181
2182 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
2183         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2184 {
2185     static const unsigned char convert_5to8[] =
2186     {
2187         0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
2188         0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
2189         0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
2190         0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
2191     };
2192     static const unsigned char convert_6to8[] =
2193     {
2194         0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
2195         0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
2196         0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
2197         0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
2198         0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
2199         0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
2200         0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
2201         0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
2202     };
2203     unsigned int x, y;
2204
2205     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2206
2207     for (y = 0; y < h; ++y)
2208     {
2209         const WORD *src_line = (const WORD *)(src + y * pitch_in);
2210         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2211         for (x = 0; x < w; ++x)
2212         {
2213             WORD pixel = src_line[x];
2214             dst_line[x] = 0xff000000
2215                     | convert_5to8[(pixel & 0xf800) >> 11] << 16
2216                     | convert_6to8[(pixel & 0x07e0) >> 5] << 8
2217                     | convert_5to8[(pixel & 0x001f)];
2218         }
2219     }
2220 }
2221
2222 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
2223         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2224 {
2225     unsigned int x, y;
2226
2227     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2228
2229     for (y = 0; y < h; ++y)
2230     {
2231         const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
2232         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2233
2234         for (x = 0; x < w; ++x)
2235         {
2236             dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
2237         }
2238     }
2239 }
2240
2241 static inline BYTE cliptobyte(int x)
2242 {
2243     return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
2244 }
2245
2246 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
2247         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2248 {
2249     int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
2250     unsigned int x, y;
2251
2252     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
2253
2254     for (y = 0; y < h; ++y)
2255     {
2256         const BYTE *src_line = src + y * pitch_in;
2257         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
2258         for (x = 0; x < w; ++x)
2259         {
2260             /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2261              *     C = Y - 16; D = U - 128; E = V - 128;
2262              *     R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2263              *     G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2264              *     B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2265              * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2266              * U and V are shared between the pixels. */
2267             if (!(x & 1)) /* For every even pixel, read new U and V. */
2268             {
2269                 d = (int) src_line[1] - 128;
2270                 e = (int) src_line[3] - 128;
2271                 r2 = 409 * e + 128;
2272                 g2 = - 100 * d - 208 * e + 128;
2273                 b2 = 516 * d + 128;
2274             }
2275             c2 = 298 * ((int) src_line[0] - 16);
2276             dst_line[x] = 0xff000000
2277                 | cliptobyte((c2 + r2) >> 8) << 16    /* red   */
2278                 | cliptobyte((c2 + g2) >> 8) << 8     /* green */
2279                 | cliptobyte((c2 + b2) >> 8);         /* blue  */
2280                 /* Scale RGB values to 0..255 range,
2281                  * then clip them if still not in range (may be negative),
2282                  * then shift them within DWORD if necessary. */
2283             src_line += 2;
2284         }
2285     }
2286 }
2287
2288 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
2289         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
2290 {
2291     unsigned int x, y;
2292     int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
2293
2294     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
2295
2296     for (y = 0; y < h; ++y)
2297     {
2298         const BYTE *src_line = src + y * pitch_in;
2299         WORD *dst_line = (WORD *)(dst + y * pitch_out);
2300         for (x = 0; x < w; ++x)
2301         {
2302             /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
2303              *     C = Y - 16; D = U - 128; E = V - 128;
2304              *     R = cliptobyte((298 * C + 409 * E + 128) >> 8);
2305              *     G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
2306              *     B = cliptobyte((298 * C + 516 * D + 128) >> 8);
2307              * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
2308              * U and V are shared between the pixels. */
2309             if (!(x & 1)) /* For every even pixel, read new U and V. */
2310             {
2311                 d = (int) src_line[1] - 128;
2312                 e = (int) src_line[3] - 128;
2313                 r2 = 409 * e + 128;
2314                 g2 = - 100 * d - 208 * e + 128;
2315                 b2 = 516 * d + 128;
2316             }
2317             c2 = 298 * ((int) src_line[0] - 16);
2318             dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11   /* red   */
2319                 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5            /* green */
2320                 | (cliptobyte((c2 + b2) >> 8) >> 3);                /* blue  */
2321                 /* Scale RGB values to 0..255 range,
2322                  * then clip them if still not in range (may be negative),
2323                  * then shift them within DWORD if necessary. */
2324             src_line += 2;
2325         }
2326     }
2327 }
2328
2329 struct d3dfmt_convertor_desc
2330 {
2331     enum wined3d_format_id from, to;
2332     void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
2333 };
2334
2335 static const struct d3dfmt_convertor_desc convertors[] =
2336 {
2337     {WINED3DFMT_R32_FLOAT,      WINED3DFMT_R16_FLOAT,       convert_r32_float_r16_float},
2338     {WINED3DFMT_B5G6R5_UNORM,   WINED3DFMT_B8G8R8X8_UNORM,  convert_r5g6b5_x8r8g8b8},
2339     {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM,  convert_a8r8g8b8_x8r8g8b8},
2340     {WINED3DFMT_YUY2,           WINED3DFMT_B8G8R8X8_UNORM,  convert_yuy2_x8r8g8b8},
2341     {WINED3DFMT_YUY2,           WINED3DFMT_B5G6R5_UNORM,    convert_yuy2_r5g6b5},
2342 };
2343
2344 static inline const struct d3dfmt_convertor_desc *find_convertor(enum wined3d_format_id from,
2345         enum wined3d_format_id to)
2346 {
2347     unsigned int i;
2348
2349     for (i = 0; i < (sizeof(convertors) / sizeof(*convertors)); ++i)
2350     {
2351         if (convertors[i].from == from && convertors[i].to == to)
2352             return &convertors[i];
2353     }
2354
2355     return NULL;
2356 }
2357
2358 /*****************************************************************************
2359  * surface_convert_format
2360  *
2361  * Creates a duplicate of a surface in a different format. Is used by Blt to
2362  * blit between surfaces with different formats.
2363  *
2364  * Parameters
2365  *  source: Source surface
2366  *  fmt: Requested destination format
2367  *
2368  *****************************************************************************/
2369 static IWineD3DSurfaceImpl *surface_convert_format(IWineD3DSurfaceImpl *source, enum wined3d_format_id to_fmt)
2370 {
2371     const struct d3dfmt_convertor_desc *conv;
2372     WINED3DLOCKED_RECT lock_src, lock_dst;
2373     IWineD3DSurface *ret = NULL;
2374     HRESULT hr;
2375
2376     conv = find_convertor(source->resource.format->id, to_fmt);
2377     if (!conv)
2378     {
2379         FIXME("Cannot find a conversion function from format %s to %s.\n",
2380                 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
2381         return NULL;
2382     }
2383
2384     IWineD3DDevice_CreateSurface((IWineD3DDevice *)source->resource.device, source->resource.width,
2385             source->resource.height, to_fmt, TRUE /* lockable */, TRUE /* discard  */, 0 /* level */,
2386             0 /* usage */, WINED3DPOOL_SCRATCH, WINED3DMULTISAMPLE_NONE /* TODO: Multisampled conversion */,
2387             0 /* MultiSampleQuality */, source->surface_type, NULL /* parent */, &wined3d_null_parent_ops, &ret);
2388     if (!ret)
2389     {
2390         ERR("Failed to create a destination surface for conversion.\n");
2391         return NULL;
2392     }
2393
2394     memset(&lock_src, 0, sizeof(lock_src));
2395     memset(&lock_dst, 0, sizeof(lock_dst));
2396
2397     hr = IWineD3DSurface_Map((IWineD3DSurface *)source, &lock_src, NULL, WINED3DLOCK_READONLY);
2398     if (FAILED(hr))
2399     {
2400         ERR("Failed to lock the source surface.\n");
2401         IWineD3DSurface_Release(ret);
2402         return NULL;
2403     }
2404     hr = IWineD3DSurface_Map(ret, &lock_dst, NULL, WINED3DLOCK_READONLY);
2405     if (FAILED(hr))
2406     {
2407         ERR("Failed to lock the destination surface.\n");
2408         IWineD3DSurface_Unmap((IWineD3DSurface *)source);
2409         IWineD3DSurface_Release(ret);
2410         return NULL;
2411     }
2412
2413     conv->convert(lock_src.pBits, lock_dst.pBits, lock_src.Pitch, lock_dst.Pitch,
2414             source->resource.width, source->resource.height);
2415
2416     IWineD3DSurface_Unmap(ret);
2417     IWineD3DSurface_Unmap((IWineD3DSurface *)source);
2418
2419     return (IWineD3DSurfaceImpl *)ret;
2420 }
2421
2422 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
2423         unsigned int bpp, UINT pitch, DWORD color)
2424 {
2425     BYTE *first;
2426     int x, y;
2427
2428     /* Do first row */
2429
2430 #define COLORFILL_ROW(type) \
2431 do { \
2432     type *d = (type *)buf; \
2433     for (x = 0; x < width; ++x) \
2434         d[x] = (type)color; \
2435 } while(0)
2436
2437     switch (bpp)
2438     {
2439         case 1:
2440             COLORFILL_ROW(BYTE);
2441             break;
2442
2443         case 2:
2444             COLORFILL_ROW(WORD);
2445             break;
2446
2447         case 3:
2448         {
2449             BYTE *d = buf;
2450             for (x = 0; x < width; ++x, d += 3)
2451             {
2452                 d[0] = (color      ) & 0xFF;
2453                 d[1] = (color >>  8) & 0xFF;
2454                 d[2] = (color >> 16) & 0xFF;
2455             }
2456             break;
2457         }
2458         case 4:
2459             COLORFILL_ROW(DWORD);
2460             break;
2461
2462         default:
2463             FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
2464             return WINED3DERR_NOTAVAILABLE;
2465     }
2466
2467 #undef COLORFILL_ROW
2468
2469     /* Now copy first row. */
2470     first = buf;
2471     for (y = 1; y < height; ++y)
2472     {
2473         buf += pitch;
2474         memcpy(buf, first, width * bpp);
2475     }
2476
2477     return WINED3D_OK;
2478 }
2479
2480 /*****************************************************************************
2481  * IWineD3DSurface::Blt, SW emulation version
2482  *
2483  * Performs a blit to a surface, with or without a source surface.
2484  * This is the main functionality of DirectDraw
2485  *****************************************************************************/
2486 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Blt(IWineD3DSurface *iface,
2487         const RECT *dst_rect, IWineD3DSurface *src_surface, const RECT *src_rect,
2488         DWORD flags, const WINEDDBLTFX *fx, WINED3DTEXTUREFILTERTYPE filter)
2489 {
2490     IWineD3DSurfaceImpl *dst_surface = (IWineD3DSurfaceImpl *)iface;
2491     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
2492     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
2493     const struct wined3d_format *src_format, *dst_format;
2494     WINED3DLOCKED_RECT dlock, slock;
2495     HRESULT ret = WINED3D_OK;
2496     const BYTE *sbuf;
2497     RECT xdst,xsrc;
2498     BYTE *dbuf;
2499     int x, y;
2500
2501     TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
2502             iface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
2503             flags, fx, debug_d3dtexturefiltertype(filter));
2504
2505     if ((dst_surface->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
2506     {
2507         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
2508         return WINEDDERR_SURFACEBUSY;
2509     }
2510
2511     /* First check for the validity of source / destination rectangles.
2512      * This was verified using a test application and by MSDN. */
2513     if (src_rect)
2514     {
2515         if (src)
2516         {
2517             if (src_rect->right < src_rect->left || src_rect->bottom < src_rect->top
2518                     || src_rect->left > src->resource.width || src_rect->left < 0
2519                     || src_rect->top > src->resource.height || src_rect->top < 0
2520                     || src_rect->right > src->resource.width || src_rect->right < 0
2521                     || src_rect->bottom > src->resource.height || src_rect->bottom < 0)
2522             {
2523                 WARN("Application gave us bad source rectangle for Blt.\n");
2524                 return WINEDDERR_INVALIDRECT;
2525             }
2526
2527             if (!src_rect->right || !src_rect->bottom
2528                     || src_rect->left == (int)src->resource.width
2529                     || src_rect->top == (int)src->resource.height)
2530             {
2531                 TRACE("Nothing to be done.\n");
2532                 return WINED3D_OK;
2533             }
2534         }
2535
2536         xsrc = *src_rect;
2537     }
2538     else if (src)
2539     {
2540         xsrc.left = 0;
2541         xsrc.top = 0;
2542         xsrc.right = src->resource.width;
2543         xsrc.bottom = src->resource.height;
2544     }
2545     else
2546     {
2547         memset(&xsrc, 0, sizeof(xsrc));
2548     }
2549
2550     if (dst_rect)
2551     {
2552         /* For the Destination rect, it can be out of bounds on the condition
2553          * that a clipper is set for the given surface. */
2554         if (!dst_surface->clipper && (dst_rect->right < dst_rect->left || dst_rect->bottom < dst_rect->top
2555                 || dst_rect->left > dst_surface->resource.width || dst_rect->left < 0
2556                 || dst_rect->top > dst_surface->resource.height || dst_rect->top < 0
2557                 || dst_rect->right > dst_surface->resource.width || dst_rect->right < 0
2558                 || dst_rect->bottom > dst_surface->resource.height || dst_rect->bottom < 0))
2559         {
2560             WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
2561             return WINEDDERR_INVALIDRECT;
2562         }
2563
2564         if (dst_rect->right <= 0 || dst_rect->bottom <= 0
2565                 || dst_rect->left >= (int)dst_surface->resource.width
2566                 || dst_rect->top >= (int)dst_surface->resource.height)
2567         {
2568             TRACE("Nothing to be done.\n");
2569             return WINED3D_OK;
2570         }
2571
2572         if (!src)
2573         {
2574             RECT full_rect;
2575
2576             full_rect.left = 0;
2577             full_rect.top = 0;
2578             full_rect.right = dst_surface->resource.width;
2579             full_rect.bottom = dst_surface->resource.height;
2580             IntersectRect(&xdst, &full_rect, dst_rect);
2581         }
2582         else
2583         {
2584             BOOL clip_horiz, clip_vert;
2585
2586             xdst = *dst_rect;
2587             clip_horiz = xdst.left < 0 || xdst.right > (int)dst_surface->resource.width;
2588             clip_vert = xdst.top < 0 || xdst.bottom > (int)dst_surface->resource.height;
2589
2590             if (clip_vert || clip_horiz)
2591             {
2592                 /* Now check if this is a special case or not... */
2593                 if ((flags & WINEDDBLT_DDFX)
2594                         || (clip_horiz && xdst.right - xdst.left != xsrc.right - xsrc.left)
2595                         || (clip_vert && xdst.bottom - xdst.top != xsrc.bottom - xsrc.top))
2596                 {
2597                     WARN("Out of screen rectangle in special case. Not handled right now.\n");
2598                     return WINED3D_OK;
2599                 }
2600
2601                 if (clip_horiz)
2602                 {
2603                     if (xdst.left < 0)
2604                     {
2605                         xsrc.left -= xdst.left;
2606                         xdst.left = 0;
2607                     }
2608                     if (xdst.right > dst_surface->resource.width)
2609                     {
2610                         xsrc.right -= (xdst.right - (int)dst_surface->resource.width);
2611                         xdst.right = (int)dst_surface->resource.width;
2612                     }
2613                 }
2614
2615                 if (clip_vert)
2616                 {
2617                     if (xdst.top < 0)
2618                     {
2619                         xsrc.top -= xdst.top;
2620                         xdst.top = 0;
2621                     }
2622                     if (xdst.bottom > dst_surface->resource.height)
2623                     {
2624                         xsrc.bottom -= (xdst.bottom - (int)dst_surface->resource.height);
2625                         xdst.bottom = (int)dst_surface->resource.height;
2626                     }
2627                 }
2628
2629                 /* And check if after clipping something is still to be done... */
2630                 if ((xdst.right <= 0) || (xdst.bottom <= 0)
2631                         || (xdst.left >= (int)dst_surface->resource.width)
2632                         || (xdst.top >= (int)dst_surface->resource.height)
2633                         || (xsrc.right <= 0) || (xsrc.bottom <= 0)
2634                         || (xsrc.left >= (int)src->resource.width)
2635                         || (xsrc.top >= (int)src->resource.height))
2636                 {
2637                     TRACE("Nothing to be done after clipping.\n");
2638                     return WINED3D_OK;
2639                 }
2640             }
2641         }
2642     }
2643     else
2644     {
2645         xdst.left = 0;
2646         xdst.top = 0;
2647         xdst.right = dst_surface->resource.width;
2648         xdst.bottom = dst_surface->resource.height;
2649     }
2650
2651     if (src == dst_surface)
2652     {
2653         IWineD3DSurface_Map(iface, &dlock, NULL, 0);
2654         slock = dlock;
2655         src_format = dst_surface->resource.format;
2656         dst_format = src_format;
2657     }
2658     else
2659     {
2660         dst_format = dst_surface->resource.format;
2661         if (src)
2662         {
2663             if (dst_surface->resource.format->id != src->resource.format->id)
2664             {
2665                 src = surface_convert_format(src, dst_format->id);
2666                 if (!src)
2667                 {
2668                     /* The conv function writes a FIXME */
2669                     WARN("Cannot convert source surface format to dest format\n");
2670                     goto release;
2671                 }
2672             }
2673             IWineD3DSurface_Map((IWineD3DSurface *)src, &slock, NULL, WINED3DLOCK_READONLY);
2674             src_format = src->resource.format;
2675         }
2676         else
2677         {
2678             src_format = dst_format;
2679         }
2680         if (dst_rect)
2681             IWineD3DSurface_Map(iface, &dlock, &xdst, 0);
2682         else
2683             IWineD3DSurface_Map(iface, &dlock, NULL, 0);
2684     }
2685
2686     if (!fx || !(fx->dwDDFX)) flags &= ~WINEDDBLT_DDFX;
2687
2688     if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_FOURCC)
2689     {
2690         if (!dst_rect || src == dst_surface)
2691         {
2692             memcpy(dlock.pBits, slock.pBits, dst_surface->resource.size);
2693             goto release;
2694         }
2695     }
2696
2697     bpp = dst_surface->resource.format->byte_count;
2698     srcheight = xsrc.bottom - xsrc.top;
2699     srcwidth = xsrc.right - xsrc.left;
2700     dstheight = xdst.bottom - xdst.top;
2701     dstwidth = xdst.right - xdst.left;
2702     width = (xdst.right - xdst.left) * bpp;
2703
2704     if (dst_rect && src != dst_surface)
2705         dbuf = dlock.pBits;
2706     else
2707         dbuf = (BYTE*)dlock.pBits+(xdst.top*dlock.Pitch)+(xdst.left*bpp);
2708
2709     if (flags & WINEDDBLT_WAIT)
2710     {
2711         flags &= ~WINEDDBLT_WAIT;
2712     }
2713     if (flags & WINEDDBLT_ASYNC)
2714     {
2715         static BOOL displayed = FALSE;
2716         if (!displayed)
2717             FIXME("Can't handle WINEDDBLT_ASYNC flag right now.\n");
2718         displayed = TRUE;
2719         flags &= ~WINEDDBLT_ASYNC;
2720     }
2721     if (flags & WINEDDBLT_DONOTWAIT)
2722     {
2723         /* WINEDDBLT_DONOTWAIT appeared in DX7 */
2724         static BOOL displayed = FALSE;
2725         if (!displayed)
2726             FIXME("Can't handle WINEDDBLT_DONOTWAIT flag right now.\n");
2727         displayed = TRUE;
2728         flags &= ~WINEDDBLT_DONOTWAIT;
2729     }
2730
2731     /* First, all the 'source-less' blits */
2732     if (flags & WINEDDBLT_COLORFILL)
2733     {
2734         ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dlock.Pitch, fx->u5.dwFillColor);
2735         flags &= ~WINEDDBLT_COLORFILL;
2736     }
2737
2738     if (flags & WINEDDBLT_DEPTHFILL)
2739     {
2740         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
2741     }
2742     if (flags & WINEDDBLT_ROP)
2743     {
2744         /* Catch some degenerate cases here. */
2745         switch (fx->dwROP)
2746         {
2747             case BLACKNESS:
2748                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,0);
2749                 break;
2750             case 0xAA0029: /* No-op */
2751                 break;
2752             case WHITENESS:
2753                 ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,dlock.Pitch,~0);
2754                 break;
2755             case SRCCOPY: /* Well, we do that below? */
2756                 break;
2757             default:
2758                 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
2759                 goto error;
2760         }
2761         flags &= ~WINEDDBLT_ROP;
2762     }
2763     if (flags & WINEDDBLT_DDROPS)
2764     {
2765         FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
2766     }
2767     /* Now the 'with source' blits. */
2768     if (src)
2769     {
2770         const BYTE *sbase;
2771         int sx, xinc, sy, yinc;
2772
2773         if (!dstwidth || !dstheight) /* Hmm... stupid program? */
2774             goto release;
2775
2776         if (filter != WINED3DTEXF_NONE && filter != WINED3DTEXF_POINT
2777                 && (srcwidth != dstwidth || srcheight != dstheight))
2778         {
2779             /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
2780             FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
2781         }
2782
2783         sbase = (BYTE*)slock.pBits+(xsrc.top*slock.Pitch)+xsrc.left*bpp;
2784         xinc = (srcwidth << 16) / dstwidth;
2785         yinc = (srcheight << 16) / dstheight;
2786
2787         if (!flags)
2788         {
2789             /* No effects, we can cheat here. */
2790             if (dstwidth == srcwidth)
2791             {
2792                 if (dstheight == srcheight)
2793                 {
2794                     /* No stretching in either direction. This needs to be as
2795                      * fast as possible. */
2796                     sbuf = sbase;
2797
2798                     /* Check for overlapping surfaces. */
2799                     if (src != dst_surface || xdst.top < xsrc.top
2800                             || xdst.right <= xsrc.left || xsrc.right <= xdst.left)
2801                     {
2802                         /* No overlap, or dst above src, so copy from top downwards. */
2803                         for (y = 0; y < dstheight; ++y)
2804                         {
2805                             memcpy(dbuf, sbuf, width);
2806                             sbuf += slock.Pitch;
2807                             dbuf += dlock.Pitch;
2808                         }
2809                     }
2810                     else if (xdst.top > xsrc.top)
2811                     {
2812                         /* Copy from bottom upwards. */
2813                         sbuf += (slock.Pitch*dstheight);
2814                         dbuf += (dlock.Pitch*dstheight);
2815                         for (y = 0; y < dstheight; ++y)
2816                         {
2817                             sbuf -= slock.Pitch;
2818                             dbuf -= dlock.Pitch;
2819                             memcpy(dbuf, sbuf, width);
2820                         }
2821                     }
2822                     else
2823                     {
2824                         /* Src and dst overlapping on the same line, use memmove. */
2825                         for (y = 0; y < dstheight; ++y)
2826                         {
2827                             memmove(dbuf, sbuf, width);
2828                             sbuf += slock.Pitch;
2829                             dbuf += dlock.Pitch;
2830                         }
2831                     }
2832                 }
2833                 else
2834                 {
2835                     /* Stretching in y direction only. */
2836                     for (y = sy = 0; y < dstheight; ++y, sy += yinc)
2837                     {
2838                         sbuf = sbase + (sy >> 16) * slock.Pitch;
2839                         memcpy(dbuf, sbuf, width);
2840                         dbuf += dlock.Pitch;
2841                     }
2842                 }
2843             }
2844             else
2845             {
2846                 /* Stretching in X direction. */
2847                 int last_sy = -1;
2848                 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
2849                 {
2850                     sbuf = sbase + (sy >> 16) * slock.Pitch;
2851
2852                     if ((sy >> 16) == (last_sy >> 16))
2853                     {
2854                         /* This source row is the same as last source row -
2855                          * Copy the already stretched row. */
2856                         memcpy(dbuf, dbuf - dlock.Pitch, width);
2857                     }
2858                     else
2859                     {
2860 #define STRETCH_ROW(type) \
2861 do { \
2862     const type *s = (const type *)sbuf; \
2863     type *d = (type *)dbuf; \
2864     for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
2865         d[x] = s[sx >> 16]; \
2866 } while(0)
2867
2868                         switch(bpp)
2869                         {
2870                             case 1:
2871                                 STRETCH_ROW(BYTE);
2872                                 break;
2873                             case 2:
2874                                 STRETCH_ROW(WORD);
2875                                 break;
2876                             case 4:
2877                                 STRETCH_ROW(DWORD);
2878                                 break;
2879                             case 3:
2880                             {
2881                                 const BYTE *s;
2882                                 BYTE *d = dbuf;
2883                                 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
2884                                 {
2885                                     DWORD pixel;
2886
2887                                     s = sbuf + 3 * (sx >> 16);
2888                                     pixel = s[0] | (s[1] << 8) | (s[2] << 16);
2889                                     d[0] = (pixel      ) & 0xff;
2890                                     d[1] = (pixel >>  8) & 0xff;
2891                                     d[2] = (pixel >> 16) & 0xff;
2892                                     d += 3;
2893                                 }
2894                                 break;
2895                             }
2896                             default:
2897                                 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
2898                                 ret = WINED3DERR_NOTAVAILABLE;
2899                                 goto error;
2900                         }
2901 #undef STRETCH_ROW
2902                     }
2903                     dbuf += dlock.Pitch;
2904                     last_sy = sy;
2905                 }
2906             }
2907         }
2908         else
2909         {
2910             LONG dstyinc = dlock.Pitch, dstxinc = bpp;
2911             DWORD keylow = 0xFFFFFFFF, keyhigh = 0, keymask = 0xFFFFFFFF;
2912             DWORD destkeylow = 0x0, destkeyhigh = 0xFFFFFFFF, destkeymask = 0xFFFFFFFF;
2913             if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
2914             {
2915                 /* The color keying flags are checked for correctness in ddraw */
2916                 if (flags & WINEDDBLT_KEYSRC)
2917                 {
2918                     keylow  = src->SrcBltCKey.dwColorSpaceLowValue;
2919                     keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
2920                 }
2921                 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
2922                 {
2923                     keylow = fx->ddckSrcColorkey.dwColorSpaceLowValue;
2924                     keyhigh = fx->ddckSrcColorkey.dwColorSpaceHighValue;
2925                 }
2926
2927                 if (flags & WINEDDBLT_KEYDEST)
2928                 {
2929                     /* Destination color keys are taken from the source surface! */
2930                     destkeylow = src->DestBltCKey.dwColorSpaceLowValue;
2931                     destkeyhigh = src->DestBltCKey.dwColorSpaceHighValue;
2932                 }
2933                 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
2934                 {
2935                     destkeylow = fx->ddckDestColorkey.dwColorSpaceLowValue;
2936                     destkeyhigh = fx->ddckDestColorkey.dwColorSpaceHighValue;
2937                 }
2938
2939                 if (bpp == 1)
2940                 {
2941                     keymask = 0xff;
2942                 }
2943                 else
2944                 {
2945                     keymask = src_format->red_mask
2946                             | src_format->green_mask
2947                             | src_format->blue_mask;
2948                 }
2949                 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
2950             }
2951
2952             if (flags & WINEDDBLT_DDFX)
2953             {
2954                 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
2955                 LONG tmpxy;
2956                 dTopLeft     = dbuf;
2957                 dTopRight    = dbuf + ((dstwidth - 1) * bpp);
2958                 dBottomLeft  = dTopLeft + ((dstheight - 1) * dlock.Pitch);
2959                 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
2960
2961                 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
2962                 {
2963                     /* I don't think we need to do anything about this flag */
2964                     WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
2965                 }
2966                 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
2967                 {
2968                     tmp          = dTopRight;
2969                     dTopRight    = dTopLeft;
2970                     dTopLeft     = tmp;
2971                     tmp          = dBottomRight;
2972                     dBottomRight = dBottomLeft;
2973                     dBottomLeft  = tmp;
2974                     dstxinc = dstxinc * -1;
2975                 }
2976                 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
2977                 {
2978                     tmp          = dTopLeft;
2979                     dTopLeft     = dBottomLeft;
2980                     dBottomLeft  = tmp;
2981                     tmp          = dTopRight;
2982                     dTopRight    = dBottomRight;
2983                     dBottomRight = tmp;
2984                     dstyinc = dstyinc * -1;
2985                 }
2986                 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
2987                 {
2988                     /* I don't think we need to do anything about this flag */
2989                     WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
2990                 }
2991                 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
2992                 {
2993                     tmp          = dBottomRight;
2994                     dBottomRight = dTopLeft;
2995                     dTopLeft     = tmp;
2996                     tmp          = dBottomLeft;
2997                     dBottomLeft  = dTopRight;
2998                     dTopRight    = tmp;
2999                     dstxinc = dstxinc * -1;
3000                     dstyinc = dstyinc * -1;
3001                 }
3002                 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
3003                 {
3004                     tmp          = dTopLeft;
3005                     dTopLeft     = dBottomLeft;
3006                     dBottomLeft  = dBottomRight;
3007                     dBottomRight = dTopRight;
3008                     dTopRight    = tmp;
3009                     tmpxy   = dstxinc;
3010                     dstxinc = dstyinc;
3011                     dstyinc = tmpxy;
3012                     dstxinc = dstxinc * -1;
3013                 }
3014                 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
3015                 {
3016                     tmp          = dTopLeft;
3017                     dTopLeft     = dTopRight;
3018                     dTopRight    = dBottomRight;
3019                     dBottomRight = dBottomLeft;
3020                     dBottomLeft  = tmp;
3021                     tmpxy   = dstxinc;
3022                     dstxinc = dstyinc;
3023                     dstyinc = tmpxy;
3024                     dstyinc = dstyinc * -1;
3025                 }
3026                 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
3027                 {
3028                     /* I don't think we need to do anything about this flag */
3029                     WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
3030                 }
3031                 dbuf = dTopLeft;
3032                 flags &= ~(WINEDDBLT_DDFX);
3033             }
3034
3035 #define COPY_COLORKEY_FX(type) \
3036 do { \
3037     const type *s; \
3038     type *d = (type *)dbuf, *dx, tmp; \
3039     for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
3040     { \
3041         s = (const type *)(sbase + (sy >> 16) * slock.Pitch); \
3042         dx = d; \
3043         for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
3044         { \
3045             tmp = s[sx >> 16]; \
3046             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
3047                     && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
3048             { \
3049                 dx[0] = tmp; \
3050             } \
3051             dx = (type *)(((BYTE *)dx) + dstxinc); \
3052         } \
3053         d = (type *)(((BYTE *)d) + dstyinc); \
3054     } \
3055 } while(0)
3056
3057             switch (bpp)
3058             {
3059                 case 1:
3060                     COPY_COLORKEY_FX(BYTE);
3061                     break;
3062                 case 2:
3063                     COPY_COLORKEY_FX(WORD);
3064                     break;
3065                 case 4:
3066                     COPY_COLORKEY_FX(DWORD);
3067                     break;
3068                 case 3:
3069                 {
3070                     const BYTE *s;
3071                     BYTE *d = dbuf, *dx;
3072                     for (y = sy = 0; y < dstheight; ++y, sy += yinc)
3073                     {
3074                         sbuf = sbase + (sy >> 16) * slock.Pitch;
3075                         dx = d;
3076                         for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
3077                         {
3078                             DWORD pixel, dpixel = 0;
3079                             s = sbuf + 3 * (sx>>16);
3080                             pixel = s[0] | (s[1] << 8) | (s[2] << 16);
3081                             dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
3082                             if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
3083                                     && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
3084                             {
3085                                 dx[0] = (pixel      ) & 0xff;
3086                                 dx[1] = (pixel >>  8) & 0xff;
3087                                 dx[2] = (pixel >> 16) & 0xff;
3088                             }
3089                             dx += dstxinc;
3090                         }
3091                         d += dstyinc;
3092                     }
3093                     break;
3094                 }
3095                 default:
3096                     FIXME("%s color-keyed blit not implemented for bpp %u!\n",
3097                           (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
3098                     ret = WINED3DERR_NOTAVAILABLE;
3099                     goto error;
3100 #undef COPY_COLORKEY_FX
3101             }
3102         }
3103     }
3104
3105 error:
3106     if (flags && FIXME_ON(d3d_surface))
3107     {
3108         FIXME("\tUnsupported flags: %#x.\n", flags);
3109     }
3110
3111 release:
3112     IWineD3DSurface_Unmap(iface);
3113     if (src && src != dst_surface)
3114         IWineD3DSurface_Unmap((IWineD3DSurface *)src);
3115     /* Release the converted surface, if any. */
3116     if (src && src_surface != (IWineD3DSurface *)src)
3117         IWineD3DSurface_Release((IWineD3DSurface *)src);
3118     return ret;
3119 }
3120
3121 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_BltFast(IWineD3DSurface *iface,
3122         DWORD dstx, DWORD dsty, IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
3123 {
3124     IWineD3DSurfaceImpl *dst_surface = (IWineD3DSurfaceImpl *)iface;
3125     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
3126     const struct wined3d_format *src_format, *dst_format;
3127     RECT lock_src, lock_dst, lock_union;
3128     WINED3DLOCKED_RECT dlock, slock;
3129     HRESULT ret = WINED3D_OK;
3130     int bpp, w, h, x, y;
3131     const BYTE *sbuf;
3132     BYTE *dbuf;
3133     RECT rsrc2;
3134
3135     TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
3136             iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
3137
3138     if ((dst_surface->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
3139     {
3140         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
3141         return WINEDDERR_SURFACEBUSY;
3142     }
3143
3144     if (!rsrc)
3145     {
3146         WARN("rsrc is NULL!\n");
3147         rsrc2.left = 0;
3148         rsrc2.top = 0;
3149         rsrc2.right = src->resource.width;
3150         rsrc2.bottom = src->resource.height;
3151         rsrc = &rsrc2;
3152     }
3153
3154     /* Check source rect for validity. Copied from normal Blt. Fixes Baldur's Gate. */
3155     if ((rsrc->bottom > src->resource.height) || (rsrc->bottom < 0)
3156             || (rsrc->top > src->resource.height) || (rsrc->top < 0)
3157             || (rsrc->left > src->resource.width) || (rsrc->left < 0)
3158             || (rsrc->right > src->resource.width) || (rsrc->right < 0)
3159             || (rsrc->right < rsrc->left) || (rsrc->bottom < rsrc->top))
3160     {
3161         WARN("Application gave us bad source rectangle for BltFast.\n");
3162         return WINEDDERR_INVALIDRECT;
3163     }
3164
3165     h = rsrc->bottom - rsrc->top;
3166     if (h > dst_surface->resource.height-dsty)
3167         h = dst_surface->resource.height-dsty;
3168     if (h > src->resource.height-rsrc->top)
3169         h = src->resource.height-rsrc->top;
3170     if (h <= 0)
3171         return WINEDDERR_INVALIDRECT;
3172
3173     w = rsrc->right - rsrc->left;
3174     if (w > dst_surface->resource.width-dstx)
3175         w = dst_surface->resource.width-dstx;
3176     if (w > src->resource.width-rsrc->left)
3177         w = src->resource.width-rsrc->left;
3178     if (w <= 0)
3179         return WINEDDERR_INVALIDRECT;
3180
3181     /* Now compute the locking rectangle... */
3182     lock_src.left = rsrc->left;
3183     lock_src.top = rsrc->top;
3184     lock_src.right = lock_src.left + w;
3185     lock_src.bottom = lock_src.top + h;
3186
3187     lock_dst.left = dstx;
3188     lock_dst.top = dsty;
3189     lock_dst.right = dstx + w;
3190     lock_dst.bottom = dsty + h;
3191
3192     bpp = dst_surface->resource.format->byte_count;
3193
3194     /* We need to lock the surfaces, or we won't get refreshes when done. */
3195     if (src == dst_surface)
3196     {
3197         int pitch;
3198
3199         UnionRect(&lock_union, &lock_src, &lock_dst);
3200
3201         /* Lock the union of the two rectangles */
3202         ret = IWineD3DSurface_Map(iface, &dlock, &lock_union, 0);
3203         if (FAILED(ret))
3204             goto error;
3205
3206         pitch = dlock.Pitch;
3207         slock.Pitch = dlock.Pitch;
3208
3209         /* Since slock was originally copied from this surface's description, we can just reuse it. */
3210         sbuf = dst_surface->resource.allocatedMemory + lock_src.top * pitch + lock_src.left * bpp;
3211         dbuf = dst_surface->resource.allocatedMemory + lock_dst.top * pitch + lock_dst.left * bpp;
3212         src_format = src->resource.format;
3213         dst_format = src_format;
3214     }
3215     else
3216     {
3217         ret = IWineD3DSurface_Map(src_surface, &slock, &lock_src, WINED3DLOCK_READONLY);
3218         if (FAILED(ret))
3219             goto error;
3220         ret = IWineD3DSurface_Map(iface, &dlock, &lock_dst, 0);
3221         if (FAILED(ret))
3222             goto error;
3223
3224         sbuf = slock.pBits;
3225         dbuf = dlock.pBits;
3226         TRACE("Dst is at %p, Src is at %p.\n", dbuf, sbuf);
3227
3228         src_format = src->resource.format;
3229         dst_format = dst_surface->resource.format;
3230     }
3231
3232     /* Handle compressed surfaces first... */
3233     if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_COMPRESSED)
3234     {
3235         UINT row_block_count;
3236
3237         TRACE("compressed -> compressed copy\n");
3238         if (trans)
3239             FIXME("trans arg not supported when a compressed surface is involved\n");
3240         if (dstx || dsty)
3241             FIXME("offset for destination surface is not supported\n");
3242         if (src->resource.format->id != dst_surface->resource.format->id)
3243         {
3244             FIXME("compressed -> compressed copy only supported for the same type of surface\n");
3245             ret = WINED3DERR_WRONGTEXTUREFORMAT;
3246             goto error;
3247         }
3248
3249         row_block_count = (w + dst_format->block_width - 1) / dst_format->block_width;
3250         for (y = 0; y < h; y += dst_format->block_height)
3251         {
3252             memcpy(dbuf, sbuf, row_block_count * dst_format->block_byte_count);
3253             dbuf += dlock.Pitch;
3254             sbuf += slock.Pitch;
3255         }
3256
3257         goto error;
3258     }
3259     if ((src_format->flags & WINED3DFMT_FLAG_COMPRESSED) && !(dst_format->flags & WINED3DFMT_FLAG_COMPRESSED))
3260     {
3261         /* TODO: Use the libtxc_dxtn.so shared library to do software
3262          * decompression. */
3263         ERR("Software decompression not supported.\n");
3264         goto error;
3265     }
3266
3267     if (trans & (WINEDDBLTFAST_SRCCOLORKEY | WINEDDBLTFAST_DESTCOLORKEY))
3268     {
3269         DWORD keylow, keyhigh;
3270         DWORD mask = src->resource.format->red_mask
3271                 | src->resource.format->green_mask
3272                 | src->resource.format->blue_mask;
3273
3274         /* For some 8-bit formats like L8 and P8 color masks don't make sense */
3275         if (!mask && bpp == 1)
3276             mask = 0xff;
3277
3278         TRACE("Color keyed copy.\n");
3279         if (trans & WINEDDBLTFAST_SRCCOLORKEY)
3280         {
3281             keylow = src->SrcBltCKey.dwColorSpaceLowValue;
3282             keyhigh = src->SrcBltCKey.dwColorSpaceHighValue;
3283         }
3284         else
3285         {
3286             /* I'm not sure if this is correct. */
3287             FIXME("WINEDDBLTFAST_DESTCOLORKEY not fully supported yet.\n");
3288             keylow = dst_surface->DestBltCKey.dwColorSpaceLowValue;
3289             keyhigh = dst_surface->DestBltCKey.dwColorSpaceHighValue;
3290         }
3291
3292 #define COPYBOX_COLORKEY(type) \
3293 do { \
3294     const type *s = (const type *)sbuf; \
3295     type *d = (type *)dbuf; \
3296     type tmp; \
3297     for (y = 0; y < h; y++) \
3298     { \
3299         for (x = 0; x < w; x++) \
3300         { \
3301             tmp = s[x]; \
3302             if ((tmp & mask) < keylow || (tmp & mask) > keyhigh) d[x] = tmp; \
3303         } \
3304         s = (const type *)((const BYTE *)s + slock.Pitch); \
3305         d = (type *)((BYTE *)d + dlock.Pitch); \
3306     } \
3307 } while(0)
3308
3309         switch (bpp)
3310         {
3311             case 1:
3312                 COPYBOX_COLORKEY(BYTE);
3313                 break;
3314             case 2:
3315                 COPYBOX_COLORKEY(WORD);
3316                 break;
3317             case 4:
3318                 COPYBOX_COLORKEY(DWORD);
3319                 break;
3320             case 3:
3321             {
3322                 const BYTE *s;
3323                 DWORD tmp;
3324                 BYTE *d;
3325                 s = sbuf;
3326                 d = dbuf;
3327                 for (y = 0; y < h; ++y)
3328                 {
3329                     for (x = 0; x < w * 3; x += 3)
3330                     {
3331                         tmp = (DWORD)s[x] + ((DWORD)s[x + 1] << 8) + ((DWORD)s[x + 2] << 16);
3332                         if (tmp < keylow || tmp > keyhigh)
3333                         {
3334                             d[x + 0] = s[x + 0];
3335                             d[x + 1] = s[x + 1];
3336                             d[x + 2] = s[x + 2];
3337                         }
3338                     }
3339                     s += slock.Pitch;
3340                     d += dlock.Pitch;
3341                 }
3342                 break;
3343             }
3344             default:
3345                 FIXME("Source color key blitting not supported for bpp %u.\n", bpp * 8);
3346                 ret = WINED3DERR_NOTAVAILABLE;
3347                 goto error;
3348         }
3349 #undef COPYBOX_COLORKEY
3350         TRACE("Copy done.\n");
3351     }
3352     else
3353     {
3354         int width = w * bpp;
3355         INT sbufpitch, dbufpitch;
3356
3357         TRACE("No color key copy.\n");
3358         /* Handle overlapping surfaces. */
3359         if (sbuf < dbuf)
3360         {
3361             sbuf += (h - 1) * slock.Pitch;
3362             dbuf += (h - 1) * dlock.Pitch;
3363             sbufpitch = -slock.Pitch;
3364             dbufpitch = -dlock.Pitch;
3365         }
3366         else
3367         {
3368             sbufpitch = slock.Pitch;
3369             dbufpitch = dlock.Pitch;
3370         }
3371         for (y = 0; y < h; ++y)
3372         {
3373             /* This is pretty easy, a line for line memcpy. */
3374             memmove(dbuf, sbuf, width);
3375             sbuf += sbufpitch;
3376             dbuf += dbufpitch;
3377         }
3378         TRACE("Copy done.\n");
3379     }
3380
3381 error:
3382     if (src == dst_surface)
3383     {
3384         IWineD3DSurface_Unmap(iface);
3385     }
3386     else
3387     {
3388         IWineD3DSurface_Unmap(iface);
3389         IWineD3DSurface_Unmap(src_surface);
3390     }
3391
3392     return ret;
3393 }
3394
3395 static HRESULT WINAPI IWineD3DBaseSurfaceImpl_Map(IWineD3DSurface *iface,
3396         WINED3DLOCKED_RECT *locked_rect, const RECT *rect, DWORD flags)
3397 {
3398     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3399
3400     TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
3401             iface, locked_rect, wine_dbgstr_rect(rect), flags);
3402
3403     locked_rect->Pitch = IWineD3DSurface_GetPitch(iface);
3404
3405     if (!rect)
3406     {
3407         locked_rect->pBits = surface->resource.allocatedMemory;
3408         surface->lockedRect.left = 0;
3409         surface->lockedRect.top = 0;
3410         surface->lockedRect.right = surface->resource.width;
3411         surface->lockedRect.bottom = surface->resource.height;
3412     }
3413     else
3414     {
3415         const struct wined3d_format *format = surface->resource.format;
3416
3417         if ((format->flags & (WINED3DFMT_FLAG_COMPRESSED | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_COMPRESSED)
3418         {
3419             /* Compressed textures are block based, so calculate the offset of
3420              * the block that contains the top-left pixel of the locked rectangle. */
3421             locked_rect->pBits = surface->resource.allocatedMemory
3422                     + ((rect->top / format->block_height) * locked_rect->Pitch)
3423                     + ((rect->left / format->block_width) * format->block_byte_count);
3424         }
3425         else
3426         {
3427             locked_rect->pBits = surface->resource.allocatedMemory
3428                     + (locked_rect->Pitch * rect->top)
3429                     + (rect->left * format->byte_count);
3430         }
3431         surface->lockedRect.left = rect->left;
3432         surface->lockedRect.top = rect->top;
3433         surface->lockedRect.right = rect->right;
3434         surface->lockedRect.bottom = rect->bottom;
3435     }
3436
3437     TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
3438     TRACE("Returning memory %p, pitch %u.\n", locked_rect->pBits, locked_rect->Pitch);
3439
3440     return WINED3D_OK;
3441 }
3442 /* Do not call while under the GL lock. */
3443 static ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface)
3444 {
3445     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
3446     ULONG refcount;
3447
3448     TRACE("Surface %p, container %p of type %#x.\n",
3449             surface, surface->container.u.base, surface->container.type);
3450
3451     switch (surface->container.type)
3452     {
3453         case WINED3D_CONTAINER_TEXTURE:
3454             return wined3d_texture_decref(surface->container.u.texture);
3455
3456         case WINED3D_CONTAINER_SWAPCHAIN:
3457             return wined3d_swapchain_decref(surface->container.u.swapchain);
3458
3459         default:
3460             ERR("Unhandled container type %#x.\n", surface->container.type);
3461         case WINED3D_CONTAINER_NONE:
3462             break;
3463     }
3464
3465     refcount = InterlockedDecrement(&surface->resource.ref);
3466     TRACE("%p decreasing refcount to %u.\n", surface, refcount);
3467
3468     if (!refcount)
3469     {
3470         surface_cleanup(surface);
3471         surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
3472
3473         TRACE("Destroyed surface %p.\n", surface);
3474         HeapFree(GetProcessHeap(), 0, surface);
3475     }
3476
3477     return refcount;
3478 }
3479
3480 /* ****************************************************
3481    IWineD3DSurface IWineD3DResource parts follow
3482    **************************************************** */
3483
3484 /* Do not call while under the GL lock. */
3485 void surface_internal_preload(IWineD3DSurfaceImpl *surface, enum WINED3DSRGB srgb)
3486 {
3487     IWineD3DDeviceImpl *device = surface->resource.device;
3488
3489     TRACE("iface %p, srgb %#x.\n", surface, srgb);
3490
3491     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
3492     {
3493         struct wined3d_texture *texture = surface->container.u.texture;
3494
3495         TRACE("Passing to container (%p).\n", texture);
3496         texture->texture_ops->texture_preload(texture, srgb);
3497     }
3498     else
3499     {
3500         struct wined3d_context *context = NULL;
3501
3502         TRACE("(%p) : About to load surface\n", surface);
3503
3504         if (!device->isInDraw) context = context_acquire(device, NULL);
3505
3506         if (surface->resource.format->id == WINED3DFMT_P8_UINT
3507                 || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
3508         {
3509             if (palette9_changed(surface))
3510             {
3511                 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
3512                 /* TODO: This is not necessarily needed with hw palettized texture support */
3513                 surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3514                 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
3515                 surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
3516             }
3517         }
3518
3519         surface_load(surface, srgb == SRGB_SRGB ? TRUE : FALSE);
3520
3521         if (surface->resource.pool == WINED3DPOOL_DEFAULT)
3522         {
3523             /* Tell opengl to try and keep this texture in video ram (well mostly) */
3524             GLclampf tmp;
3525             tmp = 0.9f;
3526             ENTER_GL();
3527             glPrioritizeTextures(1, &surface->texture_name, &tmp);
3528             LEAVE_GL();
3529         }
3530
3531         if (context) context_release(context);
3532     }
3533 }
3534
3535 static void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface)
3536 {
3537     surface_internal_preload((IWineD3DSurfaceImpl *)iface, SRGB_ANY);
3538 }
3539
3540 BOOL surface_init_sysmem(IWineD3DSurfaceImpl *surface)
3541 {
3542     if (!surface->resource.allocatedMemory)
3543     {
3544         surface->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
3545                 surface->resource.size + RESOURCE_ALIGNMENT);
3546         if (!surface->resource.heapMemory)
3547         {
3548             ERR("Out of memory\n");
3549             return FALSE;
3550         }
3551         surface->resource.allocatedMemory =
3552             (BYTE *)(((ULONG_PTR)surface->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
3553     }
3554     else
3555     {
3556         memset(surface->resource.allocatedMemory, 0, surface->resource.size);
3557     }
3558
3559     surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3560
3561     return TRUE;
3562 }
3563
3564 /* ******************************************************
3565    IWineD3DSurface IWineD3DSurface parts follow
3566    ****************************************************** */
3567
3568 /* Read the framebuffer back into the surface */
3569 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, const RECT *rect, void *dest, UINT pitch)
3570 {
3571     IWineD3DDeviceImpl *device = This->resource.device;
3572     const struct wined3d_gl_info *gl_info;
3573     struct wined3d_context *context;
3574     BYTE *mem;
3575     GLint fmt;
3576     GLint type;
3577     BYTE *row, *top, *bottom;
3578     int i;
3579     BOOL bpp;
3580     RECT local_rect;
3581     BOOL srcIsUpsideDown;
3582     GLint rowLen = 0;
3583     GLint skipPix = 0;
3584     GLint skipRow = 0;
3585
3586     if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
3587         static BOOL warned = FALSE;
3588         if(!warned) {
3589             ERR("The application tries to lock the render target, but render target locking is disabled\n");
3590             warned = TRUE;
3591         }
3592         return;
3593     }
3594
3595     context = context_acquire(device, This);
3596     context_apply_blit_state(context, device);
3597     gl_info = context->gl_info;
3598
3599     ENTER_GL();
3600
3601     /* Select the correct read buffer, and give some debug output.
3602      * There is no need to keep track of the current read buffer or reset it, every part of the code
3603      * that reads sets the read buffer as desired.
3604      */
3605     if (surface_is_offscreen(This))
3606     {
3607         /* Mapping the primary render target which is not on a swapchain.
3608          * Read from the back buffer. */
3609         TRACE("Mapping offscreen render target.\n");
3610         glReadBuffer(device->offscreenBuffer);
3611         srcIsUpsideDown = TRUE;
3612     }
3613     else
3614     {
3615         /* Onscreen surfaces are always part of a swapchain */
3616         GLenum buffer = surface_get_gl_buffer(This);
3617         TRACE("Mapping %#x buffer.\n", buffer);
3618         glReadBuffer(buffer);
3619         checkGLcall("glReadBuffer");
3620         srcIsUpsideDown = FALSE;
3621     }
3622
3623     /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
3624     if(!rect) {
3625         local_rect.left = 0;
3626         local_rect.top = 0;
3627         local_rect.right = This->resource.width;
3628         local_rect.bottom = This->resource.height;
3629     }
3630     else
3631     {
3632         local_rect = *rect;
3633     }
3634     /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
3635
3636     switch (This->resource.format->id)
3637     {
3638         case WINED3DFMT_P8_UINT:
3639         {
3640             if (primary_render_target_is_p8(device))
3641             {
3642                 /* In case of P8 render targets the index is stored in the alpha component */
3643                 fmt = GL_ALPHA;
3644                 type = GL_UNSIGNED_BYTE;
3645                 mem = dest;
3646                 bpp = This->resource.format->byte_count;
3647             } else {
3648                 /* GL can't return palettized data, so read ARGB pixels into a
3649                  * separate block of memory and convert them into palettized format
3650                  * in software. Slow, but if the app means to use palettized render
3651                  * targets and locks it...
3652                  *
3653                  * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
3654                  * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
3655                  * for the color channels when palettizing the colors.
3656                  */
3657                 fmt = GL_RGB;
3658                 type = GL_UNSIGNED_BYTE;
3659                 pitch *= 3;
3660                 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
3661                 if(!mem) {
3662                     ERR("Out of memory\n");
3663                     LEAVE_GL();
3664                     return;
3665                 }
3666                 bpp = This->resource.format->byte_count * 3;
3667             }
3668         }
3669         break;
3670
3671         default:
3672             mem = dest;
3673             fmt = This->resource.format->glFormat;
3674             type = This->resource.format->glType;
3675             bpp = This->resource.format->byte_count;
3676     }
3677
3678     if (This->flags & SFLAG_PBO)
3679     {
3680         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
3681         checkGLcall("glBindBufferARB");
3682         if (mem)
3683         {
3684             ERR("mem not null for pbo -- unexpected\n");
3685             mem = NULL;
3686         }
3687     }
3688
3689     /* Save old pixel store pack state */
3690     glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
3691     checkGLcall("glGetIntegerv");
3692     glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
3693     checkGLcall("glGetIntegerv");
3694     glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
3695     checkGLcall("glGetIntegerv");
3696
3697     /* Setup pixel store pack state -- to glReadPixels into the correct place */
3698     glPixelStorei(GL_PACK_ROW_LENGTH, This->resource.width);
3699     checkGLcall("glPixelStorei");
3700     glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
3701     checkGLcall("glPixelStorei");
3702     glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
3703     checkGLcall("glPixelStorei");
3704
3705     glReadPixels(local_rect.left, !srcIsUpsideDown ? (This->resource.height - local_rect.bottom) : local_rect.top,
3706                  local_rect.right - local_rect.left,
3707                  local_rect.bottom - local_rect.top,
3708                  fmt, type, mem);
3709     checkGLcall("glReadPixels");
3710
3711     /* Reset previous pixel store pack state */
3712     glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
3713     checkGLcall("glPixelStorei");
3714     glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
3715     checkGLcall("glPixelStorei");
3716     glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
3717     checkGLcall("glPixelStorei");
3718
3719     if (This->flags & SFLAG_PBO)
3720     {
3721         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
3722         checkGLcall("glBindBufferARB");
3723
3724         /* Check if we need to flip the image. If we need to flip use glMapBufferARB
3725          * to get a pointer to it and perform the flipping in software. This is a lot
3726          * faster than calling glReadPixels for each line. In case we want more speed
3727          * we should rerender it flipped in a FBO and read the data back from the FBO. */
3728         if(!srcIsUpsideDown) {
3729             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
3730             checkGLcall("glBindBufferARB");
3731
3732             mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
3733             checkGLcall("glMapBufferARB");
3734         }
3735     }
3736
3737     /* TODO: Merge this with the palettization loop below for P8 targets */
3738     if(!srcIsUpsideDown) {
3739         UINT len, off;
3740         /* glReadPixels returns the image upside down, and there is no way to prevent this.
3741             Flip the lines in software */
3742         len = (local_rect.right - local_rect.left) * bpp;
3743         off = local_rect.left * bpp;
3744
3745         row = HeapAlloc(GetProcessHeap(), 0, len);
3746         if(!row) {
3747             ERR("Out of memory\n");
3748             if (This->resource.format->id == WINED3DFMT_P8_UINT) HeapFree(GetProcessHeap(), 0, mem);
3749             LEAVE_GL();
3750             return;
3751         }
3752
3753         top = mem + pitch * local_rect.top;
3754         bottom = mem + pitch * (local_rect.bottom - 1);
3755         for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
3756             memcpy(row, top + off, len);
3757             memcpy(top + off, bottom + off, len);
3758             memcpy(bottom + off, row, len);
3759             top += pitch;
3760             bottom -= pitch;
3761         }
3762         HeapFree(GetProcessHeap(), 0, row);
3763
3764         /* Unmap the temp PBO buffer */
3765         if (This->flags & SFLAG_PBO)
3766         {
3767             GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
3768             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
3769         }
3770     }
3771
3772     LEAVE_GL();
3773     context_release(context);
3774
3775     /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette
3776      * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for
3777      * the same color but we have no choice.
3778      * In case of P8 render targets, the index is stored in the alpha component so no conversion is needed.
3779      */
3780     if (This->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
3781     {
3782         const PALETTEENTRY *pal = NULL;
3783         DWORD width = pitch / 3;
3784         int x, y, c;
3785
3786         if(This->palette) {
3787             pal = This->palette->palents;
3788         } else {
3789             ERR("Palette is missing, cannot perform inverse palette lookup\n");
3790             HeapFree(GetProcessHeap(), 0, mem);
3791             return ;
3792         }
3793
3794         for(y = local_rect.top; y < local_rect.bottom; y++) {
3795             for(x = local_rect.left; x < local_rect.right; x++) {
3796                 /*                      start              lines            pixels      */
3797                 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
3798                 const BYTE *green = blue  + 1;
3799                 const BYTE *red = green + 1;
3800
3801                 for(c = 0; c < 256; c++) {
3802                     if(*red   == pal[c].peRed   &&
3803                        *green == pal[c].peGreen &&
3804                        *blue  == pal[c].peBlue)
3805                     {
3806                         *((BYTE *) dest + y * width + x) = c;
3807                         break;
3808                     }
3809                 }
3810             }
3811         }
3812         HeapFree(GetProcessHeap(), 0, mem);
3813     }
3814 }
3815
3816 /* Read the framebuffer contents into a texture */
3817 static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This, BOOL srgb)
3818 {
3819     IWineD3DDeviceImpl *device = This->resource.device;
3820     const struct wined3d_gl_info *gl_info;
3821     struct wined3d_context *context;
3822
3823     if (!surface_is_offscreen(This))
3824     {
3825         /* We would need to flip onscreen surfaces, but there's no efficient
3826          * way to do that here. It makes more sense for the caller to
3827          * explicitly go through sysmem. */
3828         ERR("Not supported for onscreen targets.\n");
3829         return;
3830     }
3831
3832     /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
3833      * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
3834      * states in the stateblock, and no driver was found yet that had bugs in that regard.
3835      */
3836     context = context_acquire(device, This);
3837     gl_info = context->gl_info;
3838
3839     surface_prepare_texture(This, gl_info, srgb);
3840     surface_bind_and_dirtify(This, gl_info, srgb);
3841
3842     TRACE("Reading back offscreen render target %p.\n", This);
3843
3844     ENTER_GL();
3845
3846     glReadBuffer(device->offscreenBuffer);
3847     checkGLcall("glReadBuffer");
3848
3849     glCopyTexSubImage2D(This->texture_target, This->texture_level,
3850             0, 0, 0, 0, This->resource.width, This->resource.height);
3851     checkGLcall("glCopyTexSubImage2D");
3852
3853     LEAVE_GL();
3854
3855     context_release(context);
3856 }
3857
3858 /* Context activation is done by the caller. */
3859 static void surface_prepare_texture_internal(IWineD3DSurfaceImpl *surface,
3860         const struct wined3d_gl_info *gl_info, BOOL srgb)
3861 {
3862     DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
3863     CONVERT_TYPES convert;
3864     struct wined3d_format format;
3865
3866     if (surface->flags & alloc_flag) return;
3867
3868     d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
3869     if (convert != NO_CONVERSION || format.convert) surface->flags |= SFLAG_CONVERTED;
3870     else surface->flags &= ~SFLAG_CONVERTED;
3871
3872     surface_bind_and_dirtify(surface, gl_info, srgb);
3873     surface_allocate_surface(surface, gl_info, &format, srgb);
3874     surface->flags |= alloc_flag;
3875 }
3876
3877 /* Context activation is done by the caller. */
3878 void surface_prepare_texture(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info, BOOL srgb)
3879 {
3880     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
3881     {
3882         struct wined3d_texture *texture = surface->container.u.texture;
3883         UINT sub_count = texture->level_count * texture->layer_count;
3884         UINT i;
3885
3886         TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
3887
3888         for (i = 0; i < sub_count; ++i)
3889         {
3890             IWineD3DSurfaceImpl *s = surface_from_resource(texture->sub_resources[i]);
3891             surface_prepare_texture_internal(s, gl_info, srgb);
3892         }
3893
3894         return;
3895     }
3896
3897     surface_prepare_texture_internal(surface, gl_info, srgb);
3898 }
3899
3900 static void surface_prepare_system_memory(IWineD3DSurfaceImpl *This)
3901 {
3902     IWineD3DDeviceImpl *device = This->resource.device;
3903     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3904
3905     /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
3906      * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
3907      * changed
3908      */
3909     if (!(This->flags & SFLAG_DYNLOCK))
3910     {
3911         This->lockCount++;
3912         /* MAXLOCKCOUNT is defined in wined3d_private.h */
3913         if(This->lockCount > MAXLOCKCOUNT) {
3914             TRACE("Surface is locked regularly, not freeing the system memory copy any more\n");
3915             This->flags |= SFLAG_DYNLOCK;
3916         }
3917     }
3918
3919     /* Create a PBO for dynamically locked surfaces but don't do it for converted or non-pow2 surfaces.
3920      * Also don't create a PBO for systemmem surfaces.
3921      */
3922     if (gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] && (This->flags & SFLAG_DYNLOCK)
3923             && !(This->flags & (SFLAG_PBO | SFLAG_CONVERTED | SFLAG_NONPOW2))
3924             && (This->resource.pool != WINED3DPOOL_SYSTEMMEM))
3925     {
3926         GLenum error;
3927         struct wined3d_context *context;
3928
3929         context = context_acquire(device, NULL);
3930         ENTER_GL();
3931
3932         GL_EXTCALL(glGenBuffersARB(1, &This->pbo));
3933         error = glGetError();
3934         if (!This->pbo || error != GL_NO_ERROR)
3935             ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error), error);
3936
3937         TRACE("Attaching pbo=%#x to (%p)\n", This->pbo, This);
3938
3939         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
3940         checkGLcall("glBindBufferARB");
3941
3942         GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->resource.size + 4, This->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
3943         checkGLcall("glBufferDataARB");
3944
3945         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
3946         checkGLcall("glBindBufferARB");
3947
3948         /* We don't need the system memory anymore and we can't even use it for PBOs */
3949         if (!(This->flags & SFLAG_CLIENT))
3950         {
3951             HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
3952             This->resource.heapMemory = NULL;
3953         }
3954         This->resource.allocatedMemory = NULL;
3955         This->flags |= SFLAG_PBO;
3956         LEAVE_GL();
3957         context_release(context);
3958     }
3959     else if (!(This->resource.allocatedMemory || This->flags & SFLAG_PBO))
3960     {
3961         /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy,
3962          * or a pbo to map
3963          */
3964         if(!This->resource.heapMemory) {
3965             This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
3966         }
3967         This->resource.allocatedMemory =
3968                 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
3969         if (This->flags & SFLAG_INSYSMEM)
3970         {
3971             ERR("Surface without memory or pbo has SFLAG_INSYSMEM set!\n");
3972         }
3973     }
3974 }
3975
3976 static HRESULT WINAPI IWineD3DSurfaceImpl_Map(IWineD3DSurface *iface,
3977         WINED3DLOCKED_RECT *pLockedRect, const RECT *pRect, DWORD flags)
3978 {
3979     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3980     IWineD3DDeviceImpl *device = This->resource.device;
3981     const RECT *pass_rect = pRect;
3982
3983     TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
3984             iface, pLockedRect, wine_dbgstr_rect(pRect), flags);
3985
3986     /* This is also done in the base class, but we have to verify this before loading any data from
3987      * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag
3988      * may interfere, and all other bad things may happen
3989      */
3990     if (This->flags & SFLAG_LOCKED)
3991     {
3992         WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n");
3993         return WINED3DERR_INVALIDCALL;
3994     }
3995     This->flags |= SFLAG_LOCKED;
3996
3997     if (!(This->flags & SFLAG_LOCKABLE))
3998     {
3999         TRACE("Warning: trying to lock unlockable surf@%p\n", This);
4000     }
4001
4002     if (flags & WINED3DLOCK_DISCARD)
4003     {
4004         TRACE("WINED3DLOCK_DISCARD flag passed, marking SYSMEM as up to date.\n");
4005         surface_prepare_system_memory(This);
4006         surface_modify_location(This, SFLAG_INSYSMEM, TRUE);
4007         goto lock_end;
4008     }
4009
4010     /* surface_load_location() does not check if the rectangle specifies
4011      * the full surface. Most callers don't need that, so do it here. */
4012     if (pRect && !pRect->top && !pRect->left
4013             && pRect->right == This->resource.width
4014             && pRect->bottom == This->resource.height)
4015     {
4016         pass_rect = NULL;
4017     }
4018
4019     if (!(wined3d_settings.rendertargetlock_mode == RTL_DISABLE
4020             && ((This->container.type == WINED3D_CONTAINER_SWAPCHAIN) || This == device->render_targets[0])))
4021     {
4022         surface_load_location(This, SFLAG_INSYSMEM, pass_rect);
4023     }
4024
4025 lock_end:
4026     if (This->flags & SFLAG_PBO)
4027     {
4028         const struct wined3d_gl_info *gl_info;
4029         struct wined3d_context *context;
4030
4031         context = context_acquire(device, NULL);
4032         gl_info = context->gl_info;
4033
4034         ENTER_GL();
4035         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
4036         checkGLcall("glBindBufferARB");
4037
4038         /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */
4039         if(This->resource.allocatedMemory) {
4040             ERR("The surface already has PBO memory allocated!\n");
4041         }
4042
4043         This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
4044         checkGLcall("glMapBufferARB");
4045
4046         /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */
4047         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4048         checkGLcall("glBindBufferARB");
4049
4050         LEAVE_GL();
4051         context_release(context);
4052     }
4053
4054     if (!(flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)))
4055     {
4056         if (!pRect)
4057             surface_add_dirty_rect(This, NULL);
4058         else
4059         {
4060             WINED3DBOX b;
4061
4062             b.Left = pRect->left;
4063             b.Top = pRect->top;
4064             b.Right = pRect->right;
4065             b.Bottom = pRect->bottom;
4066             b.Front = 0;
4067             b.Back = 1;
4068             surface_add_dirty_rect(This, &b);
4069         }
4070     }
4071
4072     return IWineD3DBaseSurfaceImpl_Map(iface, pLockedRect, pRect, flags);
4073 }
4074
4075 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *surface,
4076         const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4077 {
4078     UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);    /* target is argb, 4 byte */
4079     IWineD3DDeviceImpl *device = surface->resource.device;
4080     const struct wined3d_gl_info *gl_info;
4081     struct wined3d_context *context;
4082     RECT local_rect;
4083     UINT w, h;
4084
4085     surface_get_rect(surface, rect, &local_rect);
4086
4087     mem += local_rect.top * pitch + local_rect.left * bpp;
4088     w = local_rect.right - local_rect.left;
4089     h = local_rect.bottom - local_rect.top;
4090
4091     /* Activate the correct context for the render target */
4092     context = context_acquire(device, surface);
4093     context_apply_blit_state(context, device);
4094     gl_info = context->gl_info;
4095
4096     ENTER_GL();
4097
4098     if (!surface_is_offscreen(surface))
4099     {
4100         GLenum buffer = surface_get_gl_buffer(surface);
4101         TRACE("Unlocking %#x buffer.\n", buffer);
4102         context_set_draw_buffer(context, buffer);
4103
4104         surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4105         glPixelZoom(1.0f, -1.0f);
4106     }
4107     else
4108     {
4109         /* Primary offscreen render target */
4110         TRACE("Offscreen render target.\n");
4111         context_set_draw_buffer(context, device->offscreenBuffer);
4112
4113         glPixelZoom(1.0f, 1.0f);
4114     }
4115
4116     glRasterPos3i(local_rect.left, local_rect.top, 1);
4117     checkGLcall("glRasterPos3i");
4118
4119     /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4120     glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4121
4122     if (surface->flags & SFLAG_PBO)
4123     {
4124         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4125         checkGLcall("glBindBufferARB");
4126     }
4127
4128     glDrawPixels(w, h, fmt, type, mem);
4129     checkGLcall("glDrawPixels");
4130
4131     if (surface->flags & SFLAG_PBO)
4132     {
4133         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4134         checkGLcall("glBindBufferARB");
4135     }
4136
4137     glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4138     checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4139
4140     LEAVE_GL();
4141
4142     if (wined3d_settings.strict_draw_ordering
4143             || (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
4144             && surface->container.u.swapchain->front_buffer == surface))
4145         wglFlush();
4146
4147     context_release(context);
4148 }
4149
4150 static HRESULT WINAPI IWineD3DSurfaceImpl_Unmap(IWineD3DSurface *iface)
4151 {
4152     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4153     IWineD3DDeviceImpl *device = This->resource.device;
4154     BOOL fullsurface;
4155
4156     if (!(This->flags & SFLAG_LOCKED))
4157     {
4158         WARN("trying to Unlock an unlocked surf@%p\n", This);
4159         return WINEDDERR_NOTLOCKED;
4160     }
4161
4162     This->flags &= ~SFLAG_LOCKED;
4163     memset(&This->lockedRect, 0, sizeof(This->lockedRect));
4164
4165     if (This->flags & SFLAG_PBO)
4166     {
4167         const struct wined3d_gl_info *gl_info;
4168         struct wined3d_context *context;
4169
4170         TRACE("Freeing PBO memory\n");
4171
4172         context = context_acquire(device, NULL);
4173         gl_info = context->gl_info;
4174
4175         ENTER_GL();
4176         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
4177         GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
4178         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4179         checkGLcall("glUnmapBufferARB");
4180         LEAVE_GL();
4181         context_release(context);
4182
4183         This->resource.allocatedMemory = NULL;
4184     }
4185
4186     TRACE("(%p) : dirtyfied(%d)\n", This, This->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
4187
4188     if (This->flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE))
4189     {
4190         TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
4191         goto unlock_end;
4192     }
4193
4194     if (This->container.type == WINED3D_CONTAINER_SWAPCHAIN
4195             || (device->render_targets && This == device->render_targets[0]))
4196     {
4197         if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
4198             static BOOL warned = FALSE;
4199             if(!warned) {
4200                 ERR("The application tries to write to the render target, but render target locking is disabled\n");
4201                 warned = TRUE;
4202             }
4203             goto unlock_end;
4204         }
4205
4206         if (!This->dirtyRect.left && !This->dirtyRect.top
4207                 && This->dirtyRect.right == This->resource.width
4208                 && This->dirtyRect.bottom == This->resource.height)
4209         {
4210             fullsurface = TRUE;
4211         } else {
4212             /* TODO: Proper partial rectangle tracking */
4213             fullsurface = FALSE;
4214             This->flags |= SFLAG_INSYSMEM;
4215         }
4216
4217         surface_load_location(This, SFLAG_INDRAWABLE, fullsurface ? NULL : &This->dirtyRect);
4218
4219         /* Partial rectangle tracking is not commonly implemented, it is only
4220          * done for render targets. INSYSMEM was set before to tell
4221          * surface_load_location() where to read the rectangle from.
4222          * Indrawable is set because all modifications from the partial
4223          * sysmem copy are written back to the drawable, thus the surface is
4224          * merged again in the drawable. The sysmem copy is not fully up to
4225          * date because only a subrectangle was read in Map(). */
4226         if (!fullsurface)
4227         {
4228             surface_modify_location(This, SFLAG_INDRAWABLE, TRUE);
4229             surface_evict_sysmem(This);
4230         }
4231
4232         This->dirtyRect.left   = This->resource.width;
4233         This->dirtyRect.top    = This->resource.height;
4234         This->dirtyRect.right  = 0;
4235         This->dirtyRect.bottom = 0;
4236     }
4237     else if (This->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL))
4238     {
4239         FIXME("Depth Stencil buffer locking is not implemented\n");
4240     }
4241
4242 unlock_end:
4243     /* Overlays have to be redrawn manually after changes with the GL implementation */
4244     if (This->overlay_dest)
4245         This->surface_ops->surface_draw_overlay(This);
4246
4247     return WINED3D_OK;
4248 }
4249
4250 static void surface_release_client_storage(IWineD3DSurfaceImpl *surface)
4251 {
4252     struct wined3d_context *context;
4253
4254     context = context_acquire(surface->resource.device, NULL);
4255
4256     ENTER_GL();
4257     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
4258     if (surface->texture_name)
4259     {
4260         surface_bind_and_dirtify(surface, context->gl_info, FALSE);
4261         glTexImage2D(surface->texture_target, surface->texture_level,
4262                 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
4263     }
4264     if (surface->texture_name_srgb)
4265     {
4266         surface_bind_and_dirtify(surface, context->gl_info, TRUE);
4267         glTexImage2D(surface->texture_target, surface->texture_level,
4268                 GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
4269     }
4270     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
4271
4272     LEAVE_GL();
4273     context_release(context);
4274
4275     surface_modify_location(surface, SFLAG_INSRGBTEX, FALSE);
4276     surface_modify_location(surface, SFLAG_INTEXTURE, FALSE);
4277     surface_force_reload(surface);
4278 }
4279
4280 static HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC)
4281 {
4282     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4283     WINED3DLOCKED_RECT lock;
4284     HRESULT hr;
4285     RGBQUAD col[256];
4286
4287     TRACE("(%p)->(%p)\n",This,pHDC);
4288
4289     if (This->flags & SFLAG_USERPTR)
4290     {
4291         ERR("Not supported on surfaces with an application-provided surfaces\n");
4292         return WINEDDERR_NODC;
4293     }
4294
4295     /* Give more detailed info for ddraw */
4296     if (This->flags & SFLAG_DCINUSE)
4297         return WINEDDERR_DCALREADYCREATED;
4298
4299     /* Can't GetDC if the surface is locked */
4300     if (This->flags & SFLAG_LOCKED)
4301         return WINED3DERR_INVALIDCALL;
4302
4303     memset(&lock, 0, sizeof(lock)); /* To be sure */
4304
4305     /* Create a DIB section if there isn't a hdc yet */
4306     if (!This->hDC)
4307     {
4308         if (This->flags & SFLAG_CLIENT)
4309         {
4310             surface_load_location(This, SFLAG_INSYSMEM, NULL);
4311             surface_release_client_storage(This);
4312         }
4313         hr = surface_create_dib_section(This);
4314         if(FAILED(hr)) return WINED3DERR_INVALIDCALL;
4315
4316         /* Use the dib section from now on if we are not using a PBO */
4317         if (!(This->flags & SFLAG_PBO))
4318             This->resource.allocatedMemory = This->dib.bitmap_data;
4319     }
4320
4321     /* Map the surface */
4322     hr = IWineD3DSurface_Map(iface, &lock, NULL, 0);
4323
4324     /* Sync the DIB with the PBO. This can't be done earlier because Map()
4325      * activates the allocatedMemory. */
4326     if (This->flags & SFLAG_PBO)
4327         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->dib.bitmap_size);
4328
4329     if (FAILED(hr))
4330     {
4331         ERR("IWineD3DSurface_Map failed, hr %#x.\n", hr);
4332         /* keep the dib section */
4333         return hr;
4334     }
4335
4336     if (This->resource.format->id == WINED3DFMT_P8_UINT
4337             || This->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
4338     {
4339         /* GetDC on palettized formats is unsupported in D3D9, and the method is missing in
4340             D3D8, so this should only be used for DX <=7 surfaces (with non-device palettes) */
4341         unsigned int n;
4342         const PALETTEENTRY *pal = NULL;
4343
4344         if(This->palette) {
4345             pal = This->palette->palents;
4346         } else {
4347             IWineD3DSurfaceImpl *dds_primary;
4348             struct wined3d_swapchain *swapchain;
4349             swapchain = This->resource.device->swapchains[0];
4350             dds_primary = swapchain->front_buffer;
4351             if (dds_primary && dds_primary->palette)
4352                 pal = dds_primary->palette->palents;
4353         }
4354
4355         if (pal) {
4356             for (n=0; n<256; n++) {
4357                 col[n].rgbRed   = pal[n].peRed;
4358                 col[n].rgbGreen = pal[n].peGreen;
4359                 col[n].rgbBlue  = pal[n].peBlue;
4360                 col[n].rgbReserved = 0;
4361             }
4362             SetDIBColorTable(This->hDC, 0, 256, col);
4363         }
4364     }
4365
4366     *pHDC = This->hDC;
4367     TRACE("returning %p\n",*pHDC);
4368     This->flags |= SFLAG_DCINUSE;
4369
4370     return WINED3D_OK;
4371 }
4372
4373 static HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC)
4374 {
4375     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4376
4377     TRACE("(%p)->(%p)\n",This,hDC);
4378
4379     if (!(This->flags & SFLAG_DCINUSE))
4380         return WINEDDERR_NODC;
4381
4382     if (This->hDC !=hDC) {
4383         WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
4384         return WINEDDERR_NODC;
4385     }
4386
4387     if ((This->flags & SFLAG_PBO) && This->resource.allocatedMemory)
4388     {
4389         /* Copy the contents of the DIB over to the PBO */
4390         memcpy(This->resource.allocatedMemory, This->dib.bitmap_data, This->dib.bitmap_size);
4391     }
4392
4393     /* we locked first, so unlock now */
4394     IWineD3DSurface_Unmap(iface);
4395
4396     This->flags &= ~SFLAG_DCINUSE;
4397
4398     return WINED3D_OK;
4399 }
4400
4401 /* ******************************************************
4402    IWineD3DSurface Internal (No mapping to directx api) parts follow
4403    ****************************************************** */
4404
4405 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck,
4406         BOOL use_texturing, struct wined3d_format *format, CONVERT_TYPES *convert)
4407 {
4408     BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
4409     IWineD3DDeviceImpl *device = This->resource.device;
4410     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4411     BOOL blit_supported = FALSE;
4412
4413     /* Copy the default values from the surface. Below we might perform fixups */
4414     /* TODO: get rid of color keying desc fixups by using e.g. a table. */
4415     *format = *This->resource.format;
4416     *convert = NO_CONVERSION;
4417
4418     /* Ok, now look if we have to do any conversion */
4419     switch (This->resource.format->id)
4420     {
4421         case WINED3DFMT_P8_UINT:
4422             /* Below the call to blit_supported is disabled for Wine 1.2
4423              * because the function isn't operating correctly yet. At the
4424              * moment 8-bit blits are handled in software and if certain GL
4425              * extensions are around, surface conversion is performed at
4426              * upload time. The blit_supported call recognizes it as a
4427              * destination fixup. This type of upload 'fixup' and 8-bit to
4428              * 8-bit blits need to be handled by the blit_shader.
4429              * TODO: get rid of this #if 0. */
4430 #if 0
4431             blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
4432                     &rect, This->resource.usage, This->resource.pool, This->resource.format,
4433                     &rect, This->resource.usage, This->resource.pool, This->resource.format);
4434 #endif
4435             blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
4436
4437             /* Use conversion when the blit_shader backend supports it. It only supports this in case of
4438              * texturing. Further also use conversion in case of color keying.
4439              * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
4440              * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
4441              * conflicts with this.
4442              */
4443             if (!((blit_supported && device->render_targets && This == device->render_targets[0]))
4444                     || colorkey_active || !use_texturing)
4445             {
4446                 format->glFormat = GL_RGBA;
4447                 format->glInternal = GL_RGBA;
4448                 format->glType = GL_UNSIGNED_BYTE;
4449                 format->conv_byte_count = 4;
4450                 if (colorkey_active)
4451                     *convert = CONVERT_PALETTED_CK;
4452                 else
4453                     *convert = CONVERT_PALETTED;
4454             }
4455             break;
4456
4457         case WINED3DFMT_B2G3R3_UNORM:
4458             /* **********************
4459                 GL_UNSIGNED_BYTE_3_3_2
4460                 ********************** */
4461             if (colorkey_active) {
4462                 /* This texture format will never be used.. So do not care about color keying
4463                     up until the point in time it will be needed :-) */
4464                 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
4465             }
4466             break;
4467
4468         case WINED3DFMT_B5G6R5_UNORM:
4469             if (colorkey_active)
4470             {
4471                 *convert = CONVERT_CK_565;
4472                 format->glFormat = GL_RGBA;
4473                 format->glInternal = GL_RGB5_A1;
4474                 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
4475                 format->conv_byte_count = 2;
4476             }
4477             break;
4478
4479         case WINED3DFMT_B5G5R5X1_UNORM:
4480             if (colorkey_active)
4481             {
4482                 *convert = CONVERT_CK_5551;
4483                 format->glFormat = GL_BGRA;
4484                 format->glInternal = GL_RGB5_A1;
4485                 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
4486                 format->conv_byte_count = 2;
4487             }
4488             break;
4489
4490         case WINED3DFMT_B8G8R8_UNORM:
4491             if (colorkey_active)
4492             {
4493                 *convert = CONVERT_CK_RGB24;
4494                 format->glFormat = GL_RGBA;
4495                 format->glInternal = GL_RGBA8;
4496                 format->glType = GL_UNSIGNED_INT_8_8_8_8;
4497                 format->conv_byte_count = 4;
4498             }
4499             break;
4500
4501         case WINED3DFMT_B8G8R8X8_UNORM:
4502             if (colorkey_active)
4503             {
4504                 *convert = CONVERT_RGB32_888;
4505                 format->glFormat = GL_RGBA;
4506                 format->glInternal = GL_RGBA8;
4507                 format->glType = GL_UNSIGNED_INT_8_8_8_8;
4508                 format->conv_byte_count = 4;
4509             }
4510             break;
4511
4512         default:
4513             break;
4514     }
4515
4516     return WINED3D_OK;
4517 }
4518
4519 void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey)
4520 {
4521     IWineD3DDeviceImpl *device = This->resource.device;
4522     struct wined3d_palette *pal = This->palette;
4523     BOOL index_in_alpha = FALSE;
4524     unsigned int i;
4525
4526     /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4527      * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4528      * is slow. Further RGB->P8 conversion is not possible because palettes can have
4529      * duplicate entries. Store the color key in the unused alpha component to speed the
4530      * download up and to make conversion unneeded. */
4531     index_in_alpha = primary_render_target_is_p8(device);
4532
4533     if (!pal)
4534     {
4535         UINT dxVersion = device->wined3d->dxVersion;
4536
4537         /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
4538         if (dxVersion <= 7)
4539         {
4540             ERR("This code should never get entered for DirectDraw!, expect problems\n");
4541             if (index_in_alpha)
4542             {
4543                 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4544                  * there's no palette at this time. */
4545                 for (i = 0; i < 256; i++) table[i][3] = i;
4546             }
4547         }
4548         else
4549         {
4550             /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
4551              * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
4552              * capability flag is present (wine does advertise this capability) */
4553             for (i = 0; i < 256; ++i)
4554             {
4555                 table[i][0] = device->palettes[device->currentPalette][i].peRed;
4556                 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
4557                 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
4558                 table[i][3] = device->palettes[device->currentPalette][i].peFlags;
4559             }
4560         }
4561     }
4562     else
4563     {
4564         TRACE("Using surface palette %p\n", pal);
4565         /* Get the surface's palette */
4566         for (i = 0; i < 256; ++i)
4567         {
4568             table[i][0] = pal->palents[i].peRed;
4569             table[i][1] = pal->palents[i].peGreen;
4570             table[i][2] = pal->palents[i].peBlue;
4571
4572             /* When index_in_alpha is set the palette index is stored in the
4573              * alpha component. In case of a readback we can then read
4574              * GL_ALPHA. Color keying is handled in BltOverride using a
4575              * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4576              * color key itself is passed to glAlphaFunc in other cases the
4577              * alpha component of pixels that should be masked away is set to 0. */
4578             if (index_in_alpha)
4579             {
4580                 table[i][3] = i;
4581             }
4582             else if (colorkey && (i >= This->SrcBltCKey.dwColorSpaceLowValue)
4583                     && (i <= This->SrcBltCKey.dwColorSpaceHighValue))
4584             {
4585                 table[i][3] = 0x00;
4586             }
4587             else if (pal->flags & WINEDDPCAPS_ALPHA)
4588             {
4589                 table[i][3] = pal->palents[i].peFlags;
4590             }
4591             else
4592             {
4593                 table[i][3] = 0xFF;
4594             }
4595         }
4596     }
4597 }
4598
4599 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width,
4600         UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This)
4601 {
4602     const BYTE *source;
4603     BYTE *dest;
4604     TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This);
4605
4606     switch (convert) {
4607         case NO_CONVERSION:
4608         {
4609             memcpy(dst, src, pitch * height);
4610             break;
4611         }
4612         case CONVERT_PALETTED:
4613         case CONVERT_PALETTED_CK:
4614         {
4615             BYTE table[256][4];
4616             unsigned int x, y;
4617
4618             d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
4619
4620             for (y = 0; y < height; y++)
4621             {
4622                 source = src + pitch * y;
4623                 dest = dst + outpitch * y;
4624                 /* This is an 1 bpp format, using the width here is fine */
4625                 for (x = 0; x < width; x++) {
4626                     BYTE color = *source++;
4627                     *dest++ = table[color][0];
4628                     *dest++ = table[color][1];
4629                     *dest++ = table[color][2];
4630                     *dest++ = table[color][3];
4631                 }
4632             }
4633         }
4634         break;
4635
4636         case CONVERT_CK_565:
4637         {
4638             /* Converting the 565 format in 5551 packed to emulate color-keying.
4639
4640               Note : in all these conversion, it would be best to average the averaging
4641                       pixels to get the color of the pixel that will be color-keyed to
4642                       prevent 'color bleeding'. This will be done later on if ever it is
4643                       too visible.
4644
4645               Note2: Nvidia documents say that their driver does not support alpha + color keying
4646                      on the same surface and disables color keying in such a case
4647             */
4648             unsigned int x, y;
4649             const WORD *Source;
4650             WORD *Dest;
4651
4652             TRACE("Color keyed 565\n");
4653
4654             for (y = 0; y < height; y++) {
4655                 Source = (const WORD *)(src + y * pitch);
4656                 Dest = (WORD *) (dst + y * outpitch);
4657                 for (x = 0; x < width; x++ ) {
4658                     WORD color = *Source++;
4659                     *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
4660                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4661                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4662                         *Dest |= 0x0001;
4663                     }
4664                     Dest++;
4665                 }
4666             }
4667         }
4668         break;
4669
4670         case CONVERT_CK_5551:
4671         {
4672             /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4673             unsigned int x, y;
4674             const WORD *Source;
4675             WORD *Dest;
4676             TRACE("Color keyed 5551\n");
4677             for (y = 0; y < height; y++) {
4678                 Source = (const WORD *)(src + y * pitch);
4679                 Dest = (WORD *) (dst + y * outpitch);
4680                 for (x = 0; x < width; x++ ) {
4681                     WORD color = *Source++;
4682                     *Dest = color;
4683                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4684                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4685                         *Dest |= (1 << 15);
4686                     }
4687                     else {
4688                         *Dest &= ~(1 << 15);
4689                     }
4690                     Dest++;
4691                 }
4692             }
4693         }
4694         break;
4695
4696         case CONVERT_CK_RGB24:
4697         {
4698             /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4699             unsigned int x, y;
4700             for (y = 0; y < height; y++)
4701             {
4702                 source = src + pitch * y;
4703                 dest = dst + outpitch * y;
4704                 for (x = 0; x < width; x++) {
4705                     DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
4706                     DWORD dstcolor = color << 8;
4707                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4708                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4709                         dstcolor |= 0xff;
4710                     }
4711                     *(DWORD*)dest = dstcolor;
4712                     source += 3;
4713                     dest += 4;
4714                 }
4715             }
4716         }
4717         break;
4718
4719         case CONVERT_RGB32_888:
4720         {
4721             /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4722             unsigned int x, y;
4723             for (y = 0; y < height; y++)
4724             {
4725                 source = src + pitch * y;
4726                 dest = dst + outpitch * y;
4727                 for (x = 0; x < width; x++) {
4728                     DWORD color = 0xffffff & *(const DWORD*)source;
4729                     DWORD dstcolor = color << 8;
4730                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
4731                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
4732                         dstcolor |= 0xff;
4733                     }
4734                     *(DWORD*)dest = dstcolor;
4735                     source += 4;
4736                     dest += 4;
4737                 }
4738             }
4739         }
4740         break;
4741
4742         default:
4743             ERR("Unsupported conversion type %#x.\n", convert);
4744     }
4745     return WINED3D_OK;
4746 }
4747
4748 BOOL palette9_changed(IWineD3DSurfaceImpl *This)
4749 {
4750     IWineD3DDeviceImpl *device = This->resource.device;
4751
4752     if (This->palette || (This->resource.format->id != WINED3DFMT_P8_UINT
4753             && This->resource.format->id != WINED3DFMT_P8_UINT_A8_UNORM))
4754     {
4755         /* If a ddraw-style palette is attached assume no d3d9 palette change.
4756          * Also the palette isn't interesting if the surface format isn't P8 or A8P8
4757          */
4758         return FALSE;
4759     }
4760
4761     if (This->palette9)
4762     {
4763         if (!memcmp(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256))
4764         {
4765             return FALSE;
4766         }
4767     } else {
4768         This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
4769     }
4770     memcpy(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
4771     return TRUE;
4772 }
4773
4774 static HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, enum wined3d_format_id format)
4775 {
4776     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4777     HRESULT hr;
4778
4779     TRACE("(%p) : Calling base function first\n", This);
4780     hr = IWineD3DBaseSurfaceImpl_SetFormat(iface, format);
4781     if (SUCCEEDED(hr))
4782     {
4783         This->flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
4784         TRACE("(%p) : glFormat %d, glFormatInternal %d, glType %d\n", This, This->resource.format->glFormat,
4785                 This->resource.format->glInternal, This->resource.format->glType);
4786     }
4787     return hr;
4788 }
4789
4790 static HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
4791     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4792
4793     TRACE("iface %p, mem %p.\n", iface, Mem);
4794
4795     if (This->flags & (SFLAG_LOCKED | SFLAG_DCINUSE))
4796     {
4797         WARN("Surface is locked or the HDC is in use\n");
4798         return WINED3DERR_INVALIDCALL;
4799     }
4800
4801     if(Mem && Mem != This->resource.allocatedMemory) {
4802         void *release = NULL;
4803
4804         /* Do I have to copy the old surface content? */
4805         if (This->flags & SFLAG_DIBSECTION)
4806         {
4807             SelectObject(This->hDC, This->dib.holdbitmap);
4808             DeleteDC(This->hDC);
4809             /* Release the DIB section */
4810             DeleteObject(This->dib.DIBsection);
4811             This->dib.bitmap_data = NULL;
4812             This->resource.allocatedMemory = NULL;
4813             This->hDC = NULL;
4814             This->flags &= ~SFLAG_DIBSECTION;
4815         }
4816         else if (!(This->flags & SFLAG_USERPTR))
4817         {
4818             release = This->resource.heapMemory;
4819             This->resource.heapMemory = NULL;
4820         }
4821         This->resource.allocatedMemory = Mem;
4822         This->flags |= SFLAG_USERPTR;
4823
4824         /* Now the surface memory is most up do date. Invalidate drawable and texture */
4825         surface_modify_location(This, SFLAG_INSYSMEM, TRUE);
4826
4827         /* For client textures opengl has to be notified */
4828         if (This->flags & SFLAG_CLIENT)
4829             surface_release_client_storage(This);
4830
4831         /* Now free the old memory if any */
4832         HeapFree(GetProcessHeap(), 0, release);
4833     }
4834     else if (This->flags & SFLAG_USERPTR)
4835     {
4836         /* Map and GetDC will re-create the dib section and allocated memory. */
4837         This->resource.allocatedMemory = NULL;
4838         /* HeapMemory should be NULL already */
4839         if (This->resource.heapMemory)
4840             ERR("User pointer surface has heap memory allocated.\n");
4841         This->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
4842
4843         if (This->flags & SFLAG_CLIENT)
4844             surface_release_client_storage(This);
4845
4846         surface_prepare_system_memory(This);
4847         surface_modify_location(This, SFLAG_INSYSMEM, TRUE);
4848     }
4849     return WINED3D_OK;
4850 }
4851
4852 void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back) {
4853
4854     /* Flip the surface contents */
4855     /* Flip the DC */
4856     {
4857         HDC tmp;
4858         tmp = front->hDC;
4859         front->hDC = back->hDC;
4860         back->hDC = tmp;
4861     }
4862
4863     /* Flip the DIBsection */
4864     {
4865         HBITMAP tmp;
4866         BOOL hasDib = front->flags & SFLAG_DIBSECTION;
4867         tmp = front->dib.DIBsection;
4868         front->dib.DIBsection = back->dib.DIBsection;
4869         back->dib.DIBsection = tmp;
4870
4871         if (back->flags & SFLAG_DIBSECTION) front->flags |= SFLAG_DIBSECTION;
4872         else front->flags &= ~SFLAG_DIBSECTION;
4873         if (hasDib) back->flags |= SFLAG_DIBSECTION;
4874         else back->flags &= ~SFLAG_DIBSECTION;
4875     }
4876
4877     /* Flip the surface data */
4878     {
4879         void* tmp;
4880
4881         tmp = front->dib.bitmap_data;
4882         front->dib.bitmap_data = back->dib.bitmap_data;
4883         back->dib.bitmap_data = tmp;
4884
4885         tmp = front->resource.allocatedMemory;
4886         front->resource.allocatedMemory = back->resource.allocatedMemory;
4887         back->resource.allocatedMemory = tmp;
4888
4889         tmp = front->resource.heapMemory;
4890         front->resource.heapMemory = back->resource.heapMemory;
4891         back->resource.heapMemory = tmp;
4892     }
4893
4894     /* Flip the PBO */
4895     {
4896         GLuint tmp_pbo = front->pbo;
4897         front->pbo = back->pbo;
4898         back->pbo = tmp_pbo;
4899     }
4900
4901     /* client_memory should not be different, but just in case */
4902     {
4903         BOOL tmp;
4904         tmp = front->dib.client_memory;
4905         front->dib.client_memory = back->dib.client_memory;
4906         back->dib.client_memory = tmp;
4907     }
4908
4909     /* Flip the opengl texture */
4910     {
4911         GLuint tmp;
4912
4913         tmp = back->texture_name;
4914         back->texture_name = front->texture_name;
4915         front->texture_name = tmp;
4916
4917         tmp = back->texture_name_srgb;
4918         back->texture_name_srgb = front->texture_name_srgb;
4919         front->texture_name_srgb = tmp;
4920
4921         resource_unload(&back->resource);
4922         resource_unload(&front->resource);
4923     }
4924
4925     {
4926         DWORD tmp_flags = back->flags;
4927         back->flags = front->flags;
4928         front->flags = tmp_flags;
4929     }
4930 }
4931
4932 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD flags)
4933 {
4934     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4935     struct wined3d_swapchain *swapchain = NULL;
4936
4937     TRACE("iface %p, override %p, flags %#x.\n", iface, override, flags);
4938
4939     /* Flipping is only supported on RenderTargets and overlays*/
4940     if( !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)) ) {
4941         WARN("Tried to flip a non-render target, non-overlay surface\n");
4942         return WINEDDERR_NOTFLIPPABLE;
4943     }
4944
4945     if(This->resource.usage & WINED3DUSAGE_OVERLAY) {
4946         flip_surface(This, (IWineD3DSurfaceImpl *) override);
4947
4948         /* Update the overlay if it is visible */
4949         if (This->overlay_dest)
4950             return This->surface_ops->surface_draw_overlay(This);
4951         else
4952             return WINED3D_OK;
4953     }
4954
4955     if(override) {
4956         /* DDraw sets this for the X11 surfaces, so don't confuse the user
4957          * FIXME("(%p) Target override is not supported by now\n", This);
4958          * Additionally, it isn't really possible to support triple-buffering
4959          * properly on opengl at all
4960          */
4961     }
4962
4963     if (This->container.type != WINED3D_CONTAINER_SWAPCHAIN)
4964     {
4965         ERR("Flipped surface is not on a swapchain\n");
4966         return WINEDDERR_NOTFLIPPABLE;
4967     }
4968     swapchain = This->container.u.swapchain;
4969
4970     /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
4971      * and only d3d8 and d3d9 apps specify the presentation interval
4972      */
4973     if (!(flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)))
4974         /* Most common case first to avoid wasting time on all the other cases */
4975         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
4976     else if (flags & WINEDDFLIP_NOVSYNC)
4977         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
4978     else if (flags & WINEDDFLIP_INTERVAL2)
4979         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
4980     else if (flags & WINEDDFLIP_INTERVAL3)
4981         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
4982     else
4983         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
4984
4985     /* Flipping a OpenGL surface -> present. */
4986     return wined3d_swapchain_present(swapchain, NULL, NULL, swapchain->win_handle, NULL, 0);
4987 }
4988
4989 /* Does a direct frame buffer -> texture copy. Stretching is done
4990  * with single pixel copy calls
4991  */
4992 static void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *dst_surface, IWineD3DSurfaceImpl *src_surface,
4993         const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
4994 {
4995     IWineD3DDeviceImpl *device = dst_surface->resource.device;
4996     float xrel, yrel;
4997     UINT row;
4998     struct wined3d_context *context;
4999     BOOL upsidedown = FALSE;
5000     RECT dst_rect = *dst_rect_in;
5001
5002     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5003      * glCopyTexSubImage is a bit picky about the parameters we pass to it
5004      */
5005     if(dst_rect.top > dst_rect.bottom) {
5006         UINT tmp = dst_rect.bottom;
5007         dst_rect.bottom = dst_rect.top;
5008         dst_rect.top = tmp;
5009         upsidedown = TRUE;
5010     }
5011
5012     context = context_acquire(device, src_surface);
5013     context_apply_blit_state(context, device);
5014     surface_internal_preload(dst_surface, SRGB_RGB);
5015     ENTER_GL();
5016
5017     /* Bind the target texture */
5018     glBindTexture(dst_surface->texture_target, dst_surface->texture_name);
5019     checkGLcall("glBindTexture");
5020     if (surface_is_offscreen(src_surface))
5021     {
5022         TRACE("Reading from an offscreen target\n");
5023         upsidedown = !upsidedown;
5024         glReadBuffer(device->offscreenBuffer);
5025     }
5026     else
5027     {
5028         glReadBuffer(surface_get_gl_buffer(src_surface));
5029     }
5030     checkGLcall("glReadBuffer");
5031
5032     xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
5033     yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
5034
5035     if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5036     {
5037         FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
5038
5039         if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
5040             ERR("Texture filtering not supported in direct blit\n");
5041         }
5042     }
5043     else if ((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT)
5044             && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
5045     {
5046         ERR("Texture filtering not supported in direct blit\n");
5047     }
5048
5049     if (upsidedown
5050             && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5051             && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
5052     {
5053         /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
5054
5055         glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5056                 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
5057                 src_rect->left, src_surface->resource.height - src_rect->bottom,
5058                 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5059     }
5060     else
5061     {
5062         UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
5063         /* I have to process this row by row to swap the image,
5064          * otherwise it would be upside down, so stretching in y direction
5065          * doesn't cost extra time
5066          *
5067          * However, stretching in x direction can be avoided if not necessary
5068          */
5069         for(row = dst_rect.top; row < dst_rect.bottom; row++) {
5070             if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
5071             {
5072                 /* Well, that stuff works, but it's very slow.
5073                  * find a better way instead
5074                  */
5075                 UINT col;
5076
5077                 for (col = dst_rect.left; col < dst_rect.right; ++col)
5078                 {
5079                     glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5080                             dst_rect.left + col /* x offset */, row /* y offset */,
5081                             src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
5082                 }
5083             }
5084             else
5085             {
5086                 glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
5087                         dst_rect.left /* x offset */, row /* y offset */,
5088                         src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
5089             }
5090         }
5091     }
5092     checkGLcall("glCopyTexSubImage2D");
5093
5094     LEAVE_GL();
5095     context_release(context);
5096
5097     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5098      * path is never entered
5099      */
5100     surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5101 }
5102
5103 /* Uses the hardware to stretch and flip the image */
5104 static void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *dst_surface, IWineD3DSurfaceImpl *src_surface,
5105         const RECT *src_rect, const RECT *dst_rect_in, WINED3DTEXTUREFILTERTYPE Filter)
5106 {
5107     IWineD3DDeviceImpl *device = dst_surface->resource.device;
5108     struct wined3d_swapchain *src_swapchain = NULL;
5109     GLuint src, backup = 0;
5110     float left, right, top, bottom; /* Texture coordinates */
5111     UINT fbwidth = src_surface->resource.width;
5112     UINT fbheight = src_surface->resource.height;
5113     struct wined3d_context *context;
5114     GLenum drawBuffer = GL_BACK;
5115     GLenum texture_target;
5116     BOOL noBackBufferBackup;
5117     BOOL src_offscreen;
5118     BOOL upsidedown = FALSE;
5119     RECT dst_rect = *dst_rect_in;
5120
5121     TRACE("Using hwstretch blit\n");
5122     /* Activate the Proper context for reading from the source surface, set it up for blitting */
5123     context = context_acquire(device, src_surface);
5124     context_apply_blit_state(context, device);
5125     surface_internal_preload(dst_surface, SRGB_RGB);
5126
5127     src_offscreen = surface_is_offscreen(src_surface);
5128     noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
5129     if (!noBackBufferBackup && !src_surface->texture_name)
5130     {
5131         /* Get it a description */
5132         surface_internal_preload(src_surface, SRGB_RGB);
5133     }
5134     ENTER_GL();
5135
5136     /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
5137      * This way we don't have to wait for the 2nd readback to finish to leave this function.
5138      */
5139     if (context->aux_buffers >= 2)
5140     {
5141         /* Got more than one aux buffer? Use the 2nd aux buffer */
5142         drawBuffer = GL_AUX1;
5143     }
5144     else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
5145     {
5146         /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
5147         drawBuffer = GL_AUX0;
5148     }
5149
5150     if(noBackBufferBackup) {
5151         glGenTextures(1, &backup);
5152         checkGLcall("glGenTextures");
5153         glBindTexture(GL_TEXTURE_2D, backup);
5154         checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
5155         texture_target = GL_TEXTURE_2D;
5156     } else {
5157         /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
5158          * we are reading from the back buffer, the backup can be used as source texture
5159          */
5160         texture_target = src_surface->texture_target;
5161         glBindTexture(texture_target, src_surface->texture_name);
5162         checkGLcall("glBindTexture(texture_target, src_surface->texture_name)");
5163         glEnable(texture_target);
5164         checkGLcall("glEnable(texture_target)");
5165
5166         /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
5167         src_surface->flags &= ~SFLAG_INTEXTURE;
5168     }
5169
5170     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5171      * glCopyTexSubImage is a bit picky about the parameters we pass to it
5172      */
5173     if(dst_rect.top > dst_rect.bottom) {
5174         UINT tmp = dst_rect.bottom;
5175         dst_rect.bottom = dst_rect.top;
5176         dst_rect.top = tmp;
5177         upsidedown = TRUE;
5178     }
5179
5180     if (src_offscreen)
5181     {
5182         TRACE("Reading from an offscreen target\n");
5183         upsidedown = !upsidedown;
5184         glReadBuffer(device->offscreenBuffer);
5185     }
5186     else
5187     {
5188         glReadBuffer(surface_get_gl_buffer(src_surface));
5189     }
5190
5191     /* TODO: Only back up the part that will be overwritten */
5192     glCopyTexSubImage2D(texture_target, 0,
5193                         0, 0 /* read offsets */,
5194                         0, 0,
5195                         fbwidth,
5196                         fbheight);
5197
5198     checkGLcall("glCopyTexSubImage2D");
5199
5200     /* No issue with overriding these - the sampler is dirty due to blit usage */
5201     glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
5202             wined3d_gl_mag_filter(magLookup, Filter));
5203     checkGLcall("glTexParameteri");
5204     glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
5205             wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
5206     checkGLcall("glTexParameteri");
5207
5208     if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5209         src_swapchain = src_surface->container.u.swapchain;
5210     if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
5211     {
5212         src = backup ? backup : src_surface->texture_name;
5213     }
5214     else
5215     {
5216         glReadBuffer(GL_FRONT);
5217         checkGLcall("glReadBuffer(GL_FRONT)");
5218
5219         glGenTextures(1, &src);
5220         checkGLcall("glGenTextures(1, &src)");
5221         glBindTexture(GL_TEXTURE_2D, src);
5222         checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
5223
5224         /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5225          * out for power of 2 sizes
5226          */
5227         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
5228                 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5229         checkGLcall("glTexImage2D");
5230         glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
5231                             0, 0 /* read offsets */,
5232                             0, 0,
5233                             fbwidth,
5234                             fbheight);
5235
5236         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5237         checkGLcall("glTexParameteri");
5238         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5239         checkGLcall("glTexParameteri");
5240
5241         glReadBuffer(GL_BACK);
5242         checkGLcall("glReadBuffer(GL_BACK)");
5243
5244         if(texture_target != GL_TEXTURE_2D) {
5245             glDisable(texture_target);
5246             glEnable(GL_TEXTURE_2D);
5247             texture_target = GL_TEXTURE_2D;
5248         }
5249     }
5250     checkGLcall("glEnd and previous");
5251
5252     left = src_rect->left;
5253     right = src_rect->right;
5254
5255     if (!upsidedown)
5256     {
5257         top = src_surface->resource.height - src_rect->top;
5258         bottom = src_surface->resource.height - src_rect->bottom;
5259     }
5260     else
5261     {
5262         top = src_surface->resource.height - src_rect->bottom;
5263         bottom = src_surface->resource.height - src_rect->top;
5264     }
5265
5266     if (src_surface->flags & SFLAG_NORMCOORD)
5267     {
5268         left /= src_surface->pow2Width;
5269         right /= src_surface->pow2Width;
5270         top /= src_surface->pow2Height;
5271         bottom /= src_surface->pow2Height;
5272     }
5273
5274     /* draw the source texture stretched and upside down. The correct surface is bound already */
5275     glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
5276     glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
5277
5278     context_set_draw_buffer(context, drawBuffer);
5279     glReadBuffer(drawBuffer);
5280
5281     glBegin(GL_QUADS);
5282         /* bottom left */
5283         glTexCoord2f(left, bottom);
5284         glVertex2i(0, 0);
5285
5286         /* top left */
5287         glTexCoord2f(left, top);
5288         glVertex2i(0, dst_rect.bottom - dst_rect.top);
5289
5290         /* top right */
5291         glTexCoord2f(right, top);
5292         glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5293
5294         /* bottom right */
5295         glTexCoord2f(right, bottom);
5296         glVertex2i(dst_rect.right - dst_rect.left, 0);
5297     glEnd();
5298     checkGLcall("glEnd and previous");
5299
5300     if (texture_target != dst_surface->texture_target)
5301     {
5302         glDisable(texture_target);
5303         glEnable(dst_surface->texture_target);
5304         texture_target = dst_surface->texture_target;
5305     }
5306
5307     /* Now read the stretched and upside down image into the destination texture */
5308     glBindTexture(texture_target, dst_surface->texture_name);
5309     checkGLcall("glBindTexture");
5310     glCopyTexSubImage2D(texture_target,
5311                         0,
5312                         dst_rect.left, dst_rect.top, /* xoffset, yoffset */
5313                         0, 0, /* We blitted the image to the origin */
5314                         dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5315     checkGLcall("glCopyTexSubImage2D");
5316
5317     if(drawBuffer == GL_BACK) {
5318         /* Write the back buffer backup back */
5319         if(backup) {
5320             if(texture_target != GL_TEXTURE_2D) {
5321                 glDisable(texture_target);
5322                 glEnable(GL_TEXTURE_2D);
5323                 texture_target = GL_TEXTURE_2D;
5324             }
5325             glBindTexture(GL_TEXTURE_2D, backup);
5326             checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
5327         }
5328         else
5329         {
5330             if (texture_target != src_surface->texture_target)
5331             {
5332                 glDisable(texture_target);
5333                 glEnable(src_surface->texture_target);
5334                 texture_target = src_surface->texture_target;
5335             }
5336             glBindTexture(src_surface->texture_target, src_surface->texture_name);
5337             checkGLcall("glBindTexture(src_surface->texture_target, src_surface->texture_name)");
5338         }
5339
5340         glBegin(GL_QUADS);
5341             /* top left */
5342             glTexCoord2f(0.0f, 0.0f);
5343             glVertex2i(0, fbheight);
5344
5345             /* bottom left */
5346             glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
5347             glVertex2i(0, 0);
5348
5349             /* bottom right */
5350             glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
5351                     (float)fbheight / (float)src_surface->pow2Height);
5352             glVertex2i(fbwidth, 0);
5353
5354             /* top right */
5355             glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5356             glVertex2i(fbwidth, fbheight);
5357         glEnd();
5358     }
5359     glDisable(texture_target);
5360     checkGLcall("glDisable(texture_target)");
5361
5362     /* Cleanup */
5363     if (src != src_surface->texture_name && src != backup)
5364     {
5365         glDeleteTextures(1, &src);
5366         checkGLcall("glDeleteTextures(1, &src)");
5367     }
5368     if(backup) {
5369         glDeleteTextures(1, &backup);
5370         checkGLcall("glDeleteTextures(1, &backup)");
5371     }
5372
5373     LEAVE_GL();
5374
5375     if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
5376
5377     context_release(context);
5378
5379     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5380      * path is never entered
5381      */
5382     surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5383 }
5384
5385 /* Until the blit_shader is ready, define some prototypes here. */
5386 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
5387         const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
5388         const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format);
5389
5390 /* Front buffer coordinates are always full screen coordinates, but our GL
5391  * drawable is limited to the window's client area. The sysmem and texture
5392  * copies do have the full screen size. Note that GL has a bottom-left
5393  * origin, while D3D has a top-left origin. */
5394 void surface_translate_drawable_coords(IWineD3DSurfaceImpl *surface, HWND window, RECT *rect)
5395 {
5396     UINT drawable_height;
5397
5398     if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5399             && surface == surface->container.u.swapchain->front_buffer)
5400     {
5401         POINT offset = {0, 0};
5402         RECT windowsize;
5403
5404         ScreenToClient(window, &offset);
5405         OffsetRect(rect, offset.x, offset.y);
5406
5407         GetClientRect(window, &windowsize);
5408         drawable_height = windowsize.bottom - windowsize.top;
5409     }
5410     else
5411     {
5412         drawable_height = surface->resource.height;
5413     }
5414
5415     rect->top = drawable_height - rect->top;
5416     rect->bottom = drawable_height - rect->bottom;
5417 }
5418
5419 static BOOL surface_is_full_rect(IWineD3DSurfaceImpl *surface, const RECT *r)
5420 {
5421     if ((r->left && r->right) || abs(r->right - r->left) != surface->resource.width)
5422         return FALSE;
5423     if ((r->top && r->bottom) || abs(r->bottom - r->top) != surface->resource.height)
5424         return FALSE;
5425     return TRUE;
5426 }
5427
5428 /* blit between surface locations. onscreen on different swapchains is not supported.
5429  * depth / stencil is not supported. */
5430 static void surface_blt_fbo(IWineD3DDeviceImpl *device, const WINED3DTEXTUREFILTERTYPE filter,
5431         IWineD3DSurfaceImpl *src_surface, DWORD src_location, const RECT *src_rect_in,
5432         IWineD3DSurfaceImpl *dst_surface, DWORD dst_location, const RECT *dst_rect_in)
5433 {
5434     const struct wined3d_gl_info *gl_info;
5435     struct wined3d_context *context;
5436     RECT src_rect, dst_rect;
5437     GLenum gl_filter;
5438
5439     TRACE("device %p, filter %s,\n", device, debug_d3dtexturefiltertype(filter));
5440     TRACE("src_surface %p, src_location %s, src_rect %s,\n",
5441             src_surface, debug_surflocation(src_location), wine_dbgstr_rect(src_rect_in));
5442     TRACE("dst_surface %p, dst_location %s, dst_rect %s.\n",
5443             dst_surface, debug_surflocation(dst_location), wine_dbgstr_rect(dst_rect_in));
5444
5445     src_rect = *src_rect_in;
5446     dst_rect = *dst_rect_in;
5447
5448     switch (filter)
5449     {
5450         case WINED3DTEXF_LINEAR:
5451             gl_filter = GL_LINEAR;
5452             break;
5453
5454         default:
5455             FIXME("Unsupported filter mode %s (%#x).\n", debug_d3dtexturefiltertype(filter), filter);
5456         case WINED3DTEXF_NONE:
5457         case WINED3DTEXF_POINT:
5458             gl_filter = GL_NEAREST;
5459             break;
5460     }
5461
5462     if (src_location == SFLAG_INDRAWABLE && surface_is_offscreen(src_surface))
5463         src_location = SFLAG_INTEXTURE;
5464     if (dst_location == SFLAG_INDRAWABLE && surface_is_offscreen(dst_surface))
5465         dst_location = SFLAG_INTEXTURE;
5466
5467     /* Make sure the locations are up-to-date. Loading the destination
5468      * surface isn't required if the entire surface is overwritten. (And is
5469      * in fact harmful if we're being called by surface_load_location() with
5470      * the purpose of loading the destination surface.) */
5471     surface_load_location(src_surface, src_location, NULL);
5472     if (!surface_is_full_rect(dst_surface, &dst_rect))
5473         surface_load_location(dst_surface, dst_location, NULL);
5474
5475     if (src_location == SFLAG_INDRAWABLE) context = context_acquire(device, src_surface);
5476     else if (dst_location == SFLAG_INDRAWABLE) context = context_acquire(device, dst_surface);
5477     else context = context_acquire(device, NULL);
5478
5479     if (!context->valid)
5480     {
5481         context_release(context);
5482         WARN("Invalid context, skipping blit.\n");
5483         return;
5484     }
5485
5486     gl_info = context->gl_info;
5487
5488     if (src_location == SFLAG_INDRAWABLE)
5489     {
5490         GLenum buffer = surface_get_gl_buffer(src_surface);
5491
5492         TRACE("Source surface %p is onscreen.\n", src_surface);
5493
5494         surface_translate_drawable_coords(src_surface, context->win_handle, &src_rect);
5495
5496         ENTER_GL();
5497         context_bind_fbo(context, GL_READ_FRAMEBUFFER, NULL);
5498         glReadBuffer(buffer);
5499         checkGLcall("glReadBuffer()");
5500     }
5501     else
5502     {
5503         TRACE("Source surface %p is offscreen.\n", src_surface);
5504         ENTER_GL();
5505         context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, src_surface, NULL, src_location);
5506         glReadBuffer(GL_COLOR_ATTACHMENT0);
5507         checkGLcall("glReadBuffer()");
5508     }
5509     context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
5510     LEAVE_GL();
5511
5512     if (dst_location == SFLAG_INDRAWABLE)
5513     {
5514         GLenum buffer = surface_get_gl_buffer(dst_surface);
5515
5516         TRACE("Destination surface %p is onscreen.\n", dst_surface);
5517
5518         surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5519
5520         ENTER_GL();
5521         context_bind_fbo(context, GL_DRAW_FRAMEBUFFER, NULL);
5522         context_set_draw_buffer(context, buffer);
5523     }
5524     else
5525     {
5526         TRACE("Destination surface %p is offscreen.\n", dst_surface);
5527
5528         ENTER_GL();
5529         context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, dst_surface, NULL, dst_location);
5530         context_set_draw_buffer(context, GL_COLOR_ATTACHMENT0);
5531     }
5532     context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
5533
5534     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5535     IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5536     IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE1));
5537     IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE2));
5538     IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_COLORWRITEENABLE3));
5539
5540     glDisable(GL_SCISSOR_TEST);
5541     IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5542
5543     gl_info->fbo_ops.glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
5544             dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, gl_filter);
5545     checkGLcall("glBlitFramebuffer()");
5546
5547     LEAVE_GL();
5548
5549     if (wined3d_settings.strict_draw_ordering
5550             || (dst_location == SFLAG_INDRAWABLE
5551             && dst_surface->container.u.swapchain->front_buffer == dst_surface))
5552         wglFlush();
5553
5554     context_release(context);
5555 }
5556
5557 static void wined3d_surface_depth_blt_fbo(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *src_surface,
5558         const RECT *src_rect, IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect)
5559 {
5560     const struct wined3d_gl_info *gl_info;
5561     struct wined3d_context *context;
5562     DWORD src_mask, dst_mask;
5563     GLbitfield gl_mask;
5564
5565     TRACE("device %p, src_surface %p, src_rect %s, dst_surface %p, dst_rect %s.\n",
5566             device, src_surface, wine_dbgstr_rect(src_rect),
5567             dst_surface, wine_dbgstr_rect(dst_rect));
5568
5569     src_mask = src_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
5570     dst_mask = dst_surface->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
5571
5572     if (src_mask != dst_mask)
5573     {
5574         ERR("Incompatible formats %s and %s.\n",
5575                 debug_d3dformat(src_surface->resource.format->id),
5576                 debug_d3dformat(dst_surface->resource.format->id));
5577         return;
5578     }
5579
5580     if (!src_mask)
5581     {
5582         ERR("Not a depth / stencil format: %s.\n",
5583                 debug_d3dformat(src_surface->resource.format->id));
5584         return;
5585     }
5586
5587     gl_mask = 0;
5588     if (src_mask & WINED3DFMT_FLAG_DEPTH)
5589         gl_mask |= GL_DEPTH_BUFFER_BIT;
5590     if (src_mask & WINED3DFMT_FLAG_STENCIL)
5591         gl_mask |= GL_STENCIL_BUFFER_BIT;
5592
5593     /* Make sure the locations are up-to-date. Loading the destination
5594      * surface isn't required if the entire surface is overwritten. */
5595     surface_load_location(src_surface, SFLAG_INTEXTURE, NULL);
5596     if (!surface_is_full_rect(dst_surface, dst_rect))
5597         surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
5598
5599     context = context_acquire(device, NULL);
5600     if (!context->valid)
5601     {
5602         context_release(context);
5603         WARN("Invalid context, skipping blit.\n");
5604         return;
5605     }
5606
5607     gl_info = context->gl_info;
5608
5609     ENTER_GL();
5610
5611     context_apply_fbo_state_blit(context, GL_READ_FRAMEBUFFER, NULL, src_surface, SFLAG_INTEXTURE);
5612     glReadBuffer(GL_NONE);
5613     checkGLcall("glReadBuffer()");
5614     context_check_fbo_status(context, GL_READ_FRAMEBUFFER);
5615
5616     context_apply_fbo_state_blit(context, GL_DRAW_FRAMEBUFFER, NULL, dst_surface, SFLAG_INTEXTURE);
5617     context_set_draw_buffer(context, GL_NONE);
5618     context_check_fbo_status(context, GL_DRAW_FRAMEBUFFER);
5619
5620     if (gl_mask & GL_DEPTH_BUFFER_BIT)
5621     {
5622         glDepthMask(GL_TRUE);
5623         IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5624     }
5625     if (gl_mask & GL_STENCIL_BUFFER_BIT)
5626     {
5627         if (context->gl_info->supported[EXT_STENCIL_TWO_SIDE])
5628         {
5629             glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
5630             IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_TWOSIDEDSTENCILMODE));
5631         }
5632         glStencilMask(~0U);
5633         IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
5634     }
5635
5636     glDisable(GL_SCISSOR_TEST);
5637     IWineD3DDeviceImpl_MarkStateDirty(device, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5638
5639     gl_info->fbo_ops.glBlitFramebuffer(src_rect->left, src_rect->top, src_rect->right, src_rect->bottom,
5640             dst_rect->left, dst_rect->top, dst_rect->right, dst_rect->bottom, gl_mask, GL_NEAREST);
5641     checkGLcall("glBlitFramebuffer()");
5642
5643     LEAVE_GL();
5644
5645     if (wined3d_settings.strict_draw_ordering)
5646         wglFlush(); /* Flush to ensure ordering across contexts. */
5647
5648     context_release(context);
5649 }
5650
5651 static void surface_blt_to_drawable(IWineD3DDeviceImpl *device,
5652         WINED3DTEXTUREFILTERTYPE filter, BOOL color_key,
5653         IWineD3DSurfaceImpl *src_surface, const RECT *src_rect_in,
5654         IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect_in)
5655 {
5656     struct wined3d_context *context;
5657     RECT src_rect, dst_rect;
5658
5659     src_rect = *src_rect_in;
5660     dst_rect = *dst_rect_in;
5661
5662     /* Make sure the surface is up-to-date. This should probably use
5663      * surface_load_location() and worry about the destination surface too,
5664      * unless we're overwriting it completely. */
5665     surface_internal_preload(src_surface, SRGB_RGB);
5666
5667     /* Activate the destination context, set it up for blitting */
5668     context = context_acquire(device, dst_surface);
5669     context_apply_blit_state(context, device);
5670
5671     if (!surface_is_offscreen(dst_surface))
5672         surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5673
5674     device->blitter->set_shader(device->blit_priv, context->gl_info, src_surface);
5675
5676     ENTER_GL();
5677
5678     if (color_key)
5679     {
5680         glEnable(GL_ALPHA_TEST);
5681         checkGLcall("glEnable(GL_ALPHA_TEST)");
5682
5683         /* When the primary render target uses P8, the alpha component
5684          * contains the palette index. Which means that the colorkey is one of
5685          * the palette entries. In other cases pixels that should be masked
5686          * away have alpha set to 0. */
5687         if (primary_render_target_is_p8(device))
5688             glAlphaFunc(GL_NOTEQUAL, (float)src_surface->SrcBltCKey.dwColorSpaceLowValue / 256.0f);
5689         else
5690             glAlphaFunc(GL_NOTEQUAL, 0.0f);
5691         checkGLcall("glAlphaFunc");
5692     }
5693     else
5694     {
5695         glDisable(GL_ALPHA_TEST);
5696         checkGLcall("glDisable(GL_ALPHA_TEST)");
5697     }
5698
5699     draw_textured_quad(src_surface, &src_rect, &dst_rect, filter);
5700
5701     if (color_key)
5702     {
5703         glDisable(GL_ALPHA_TEST);
5704         checkGLcall("glDisable(GL_ALPHA_TEST)");
5705     }
5706
5707     LEAVE_GL();
5708
5709     /* Leave the opengl state valid for blitting */
5710     device->blitter->unset_shader(context->gl_info);
5711
5712     if (wined3d_settings.strict_draw_ordering
5713             || (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5714             && (dst_surface->container.u.swapchain->front_buffer == dst_surface)))
5715         wglFlush(); /* Flush to ensure ordering across contexts. */
5716
5717     context_release(context);
5718 }
5719
5720 /* Do not call while under the GL lock. */
5721 HRESULT surface_color_fill(IWineD3DSurfaceImpl *s, const RECT *rect, const WINED3DCOLORVALUE *color)
5722 {
5723     IWineD3DDeviceImpl *device = s->resource.device;
5724     const struct blit_shader *blitter;
5725
5726     blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5727             NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5728     if (!blitter)
5729     {
5730         FIXME("No blitter is capable of performing the requested color fill operation.\n");
5731         return WINED3DERR_INVALIDCALL;
5732     }
5733
5734     return blitter->color_fill(device, s, rect, color);
5735 }
5736
5737 /* Not called from the VTable */
5738 /* Do not call while under the GL lock. */
5739 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *dst_surface, const RECT *DestRect,
5740         IWineD3DSurfaceImpl *src_surface, const RECT *SrcRect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5741         WINED3DTEXTUREFILTERTYPE Filter)
5742 {
5743     IWineD3DDeviceImpl *device = dst_surface->resource.device;
5744     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5745     struct wined3d_swapchain *srcSwapchain = NULL, *dstSwapchain = NULL;
5746     RECT dst_rect, src_rect;
5747
5748     TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5749             dst_surface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
5750             flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
5751
5752     /* Get the swapchain. One of the surfaces has to be a primary surface */
5753     if (dst_surface->resource.pool == WINED3DPOOL_SYSTEMMEM)
5754     {
5755         WARN("Destination is in sysmem, rejecting gl blt\n");
5756         return WINED3DERR_INVALIDCALL;
5757     }
5758
5759     if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5760         dstSwapchain = dst_surface->container.u.swapchain;
5761
5762     if (src_surface)
5763     {
5764         if (src_surface->resource.pool == WINED3DPOOL_SYSTEMMEM)
5765         {
5766             WARN("Src is in sysmem, rejecting gl blt\n");
5767             return WINED3DERR_INVALIDCALL;
5768         }
5769
5770         if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5771             srcSwapchain = src_surface->container.u.swapchain;
5772     }
5773
5774     /* Early sort out of cases where no render target is used */
5775     if (!dstSwapchain && !srcSwapchain
5776             && src_surface != device->render_targets[0]
5777             && dst_surface != device->render_targets[0])
5778     {
5779         TRACE("No surface is render target, not using hardware blit.\n");
5780         return WINED3DERR_INVALIDCALL;
5781     }
5782
5783     /* No destination color keying supported */
5784     if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5785     {
5786         /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5787         TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5788         return WINED3DERR_INVALIDCALL;
5789     }
5790
5791     surface_get_rect(dst_surface, DestRect, &dst_rect);
5792     if (src_surface) surface_get_rect(src_surface, SrcRect, &src_rect);
5793
5794     /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
5795     if (dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->back_buffers
5796             && dst_surface == dstSwapchain->front_buffer
5797             && src_surface == dstSwapchain->back_buffers[0])
5798     {
5799         /* Half-Life does a Blt from the back buffer to the front buffer,
5800          * Full surface size, no flags... Use present instead
5801          *
5802          * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
5803          */
5804
5805         /* Check rects - IWineD3DDevice_Present doesn't handle them */
5806         while(1)
5807         {
5808             TRACE("Looking if a Present can be done...\n");
5809             /* Source Rectangle must be full surface */
5810             if (src_rect.left || src_rect.top
5811                     || src_rect.right != src_surface->resource.width
5812                     || src_rect.bottom != src_surface->resource.height)
5813             {
5814                 TRACE("No, Source rectangle doesn't match\n");
5815                 break;
5816             }
5817
5818             /* No stretching may occur */
5819             if(src_rect.right != dst_rect.right - dst_rect.left ||
5820                src_rect.bottom != dst_rect.bottom - dst_rect.top) {
5821                 TRACE("No, stretching is done\n");
5822                 break;
5823             }
5824
5825             /* Destination must be full surface or match the clipping rectangle */
5826             if (dst_surface->clipper && dst_surface->clipper->hWnd)
5827             {
5828                 RECT cliprect;
5829                 POINT pos[2];
5830                 GetClientRect(dst_surface->clipper->hWnd, &cliprect);
5831                 pos[0].x = dst_rect.left;
5832                 pos[0].y = dst_rect.top;
5833                 pos[1].x = dst_rect.right;
5834                 pos[1].y = dst_rect.bottom;
5835                 MapWindowPoints(GetDesktopWindow(), dst_surface->clipper->hWnd, pos, 2);
5836
5837                 if(pos[0].x != cliprect.left  || pos[0].y != cliprect.top   ||
5838                    pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
5839                 {
5840                     TRACE("No, dest rectangle doesn't match(clipper)\n");
5841                     TRACE("Clip rect at %s\n", wine_dbgstr_rect(&cliprect));
5842                     TRACE("Blt dest: %s\n", wine_dbgstr_rect(&dst_rect));
5843                     break;
5844                 }
5845             }
5846             else if (dst_rect.left || dst_rect.top
5847                     || dst_rect.right != dst_surface->resource.width
5848                     || dst_rect.bottom != dst_surface->resource.height)
5849             {
5850                 TRACE("No, dest rectangle doesn't match(surface size)\n");
5851                 break;
5852             }
5853
5854             TRACE("Yes\n");
5855
5856             /* These flags are unimportant for the flag check, remove them */
5857             if (!(flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)))
5858             {
5859                 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
5860
5861                 /* The idea behind this is that a glReadPixels and a glDrawPixels call
5862                     * take very long, while a flip is fast.
5863                     * This applies to Half-Life, which does such Blts every time it finished
5864                     * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
5865                     * menu. This is also used by all apps when they do windowed rendering
5866                     *
5867                     * The problem is that flipping is not really the same as copying. After a
5868                     * Blt the front buffer is a copy of the back buffer, and the back buffer is
5869                     * untouched. Therefore it's necessary to override the swap effect
5870                     * and to set it back after the flip.
5871                     *
5872                     * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
5873                     * testcases.
5874                     */
5875
5876                 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
5877                 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
5878
5879                 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead.\n");
5880                 wined3d_swapchain_present(dstSwapchain, NULL, NULL, dstSwapchain->win_handle, NULL, 0);
5881
5882                 dstSwapchain->presentParms.SwapEffect = orig_swap;
5883
5884                 return WINED3D_OK;
5885             }
5886             break;
5887         }
5888
5889         TRACE("Unsupported blit between buffers on the same swapchain\n");
5890         return WINED3DERR_INVALIDCALL;
5891     } else if(dstSwapchain && dstSwapchain == srcSwapchain) {
5892         FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5893         return WINED3DERR_INVALIDCALL;
5894     } else if(dstSwapchain && srcSwapchain) {
5895         FIXME("Implement hardware blit between two different swapchains\n");
5896         return WINED3DERR_INVALIDCALL;
5897     }
5898     else if (dstSwapchain)
5899     {
5900         /* Handled with regular texture -> swapchain blit */
5901         if (src_surface == device->render_targets[0])
5902             TRACE("Blit from active render target to a swapchain\n");
5903     }
5904     else if (srcSwapchain && dst_surface == device->render_targets[0])
5905     {
5906         FIXME("Implement blit from a swapchain to the active render target\n");
5907         return WINED3DERR_INVALIDCALL;
5908     }
5909
5910     if ((srcSwapchain || src_surface == device->render_targets[0]) && !dstSwapchain)
5911     {
5912         /* Blit from render target to texture */
5913         BOOL stretchx;
5914
5915         /* P8 read back is not implemented */
5916         if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5917                 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5918         {
5919             TRACE("P8 read back not supported by frame buffer to texture blit\n");
5920             return WINED3DERR_INVALIDCALL;
5921         }
5922
5923         if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5924         {
5925             TRACE("Color keying not supported by frame buffer to texture blit\n");
5926             return WINED3DERR_INVALIDCALL;
5927             /* Destination color key is checked above */
5928         }
5929
5930         if(dst_rect.right - dst_rect.left != src_rect.right - src_rect.left) {
5931             stretchx = TRUE;
5932         } else {
5933             stretchx = FALSE;
5934         }
5935
5936         /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5937          * flip the image nor scale it.
5938          *
5939          * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5940          * -> If the app wants a image width an unscaled width, copy it line per line
5941          * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5942          *    than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5943          *    back buffer. This is slower than reading line per line, thus not used for flipping
5944          * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5945          *    pixel by pixel
5946          *
5947          * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
5948          * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
5949          * backends. */
5950         if (fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5951                 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5952                 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5953         {
5954             surface_blt_fbo(device, Filter,
5955                     src_surface, SFLAG_INDRAWABLE, &src_rect,
5956                     dst_surface, SFLAG_INDRAWABLE, &dst_rect);
5957             surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
5958         }
5959         else if (!stretchx || dst_rect.right - dst_rect.left > src_surface->resource.width
5960                 || dst_rect.bottom - dst_rect.top > src_surface->resource.height)
5961         {
5962             TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
5963             fb_copy_to_texture_direct(dst_surface, src_surface, &src_rect, &dst_rect, Filter);
5964         } else {
5965             TRACE("Using hardware stretching to flip / stretch the texture\n");
5966             fb_copy_to_texture_hwstretch(dst_surface, src_surface, &src_rect, &dst_rect, Filter);
5967         }
5968
5969         if (!(dst_surface->flags & SFLAG_DONOTFREE))
5970         {
5971             HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5972             dst_surface->resource.allocatedMemory = NULL;
5973             dst_surface->resource.heapMemory = NULL;
5974         }
5975         else
5976         {
5977             dst_surface->flags &= ~SFLAG_INSYSMEM;
5978         }
5979
5980         return WINED3D_OK;
5981     }
5982     else if (src_surface)
5983     {
5984         /* Blit from offscreen surface to render target */
5985         DWORD oldCKeyFlags = src_surface->CKeyFlags;
5986         WINEDDCOLORKEY oldBltCKey = src_surface->SrcBltCKey;
5987
5988         TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5989
5990         if (!(flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5991                 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5992                         &src_rect, src_surface->resource.usage, src_surface->resource.pool,
5993                         src_surface->resource.format,
5994                         &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
5995                         dst_surface->resource.format))
5996         {
5997             TRACE("Using surface_blt_fbo.\n");
5998             /* The source is always a texture, but never the currently active render target, and the texture
5999              * contents are never upside down. */
6000             surface_blt_fbo(device, Filter,
6001                     src_surface, SFLAG_INDRAWABLE, &src_rect,
6002                     dst_surface, SFLAG_INDRAWABLE, &dst_rect);
6003             surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
6004             return WINED3D_OK;
6005         }
6006
6007         if (!(flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
6008                 && arbfp_blit.blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6009                         &src_rect, src_surface->resource.usage, src_surface->resource.pool,
6010                         src_surface->resource.format,
6011                         &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool,
6012                         dst_surface->resource.format))
6013         {
6014             return arbfp_blit_surface(device, src_surface, &src_rect, dst_surface, &dst_rect,
6015                     WINED3D_BLIT_OP_COLOR_BLIT, Filter);
6016         }
6017
6018         if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6019                 &src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
6020                 &dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
6021         {
6022             FIXME("Unsupported blit operation falling back to software\n");
6023             return WINED3DERR_INVALIDCALL;
6024         }
6025
6026         /* Color keying: Check if we have to do a color keyed blt,
6027          * and if not check if a color key is activated.
6028          *
6029          * Just modify the color keying parameters in the surface and restore them afterwards
6030          * The surface keeps track of the color key last used to load the opengl surface.
6031          * PreLoad will catch the change to the flags and color key and reload if necessary.
6032          */
6033         if (flags & WINEDDBLT_KEYSRC)
6034         {
6035             /* Use color key from surface */
6036         }
6037         else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
6038         {
6039             /* Use color key from DDBltFx */
6040             src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
6041             src_surface->SrcBltCKey = DDBltFx->ddckSrcColorkey;
6042         }
6043         else
6044         {
6045             /* Do not use color key */
6046             src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
6047         }
6048
6049         surface_blt_to_drawable(device, Filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
6050                 src_surface, &src_rect, dst_surface, &dst_rect);
6051
6052         /* Restore the color key parameters */
6053         src_surface->CKeyFlags = oldCKeyFlags;
6054         src_surface->SrcBltCKey = oldBltCKey;
6055
6056         surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
6057
6058         return WINED3D_OK;
6059     }
6060     else
6061     {
6062         /* Source-Less Blit to render target */
6063         if (flags & WINEDDBLT_COLORFILL)
6064         {
6065             WINED3DCOLORVALUE color;
6066
6067             TRACE("Colorfill\n");
6068
6069             /* The color as given in the Blt function is in the surface format. */
6070             if (!surface_convert_color_to_float(dst_surface, DDBltFx->u5.dwFillColor, &color))
6071                 return WINED3DERR_INVALIDCALL;
6072
6073             return surface_color_fill(dst_surface, &dst_rect, &color);
6074         }
6075     }
6076
6077     /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
6078     TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
6079     return WINED3DERR_INVALIDCALL;
6080 }
6081
6082 /* Do not call while under the GL lock. */
6083 static HRESULT wined3d_surface_depth_fill(IWineD3DSurfaceImpl *surface, const RECT *rect, float depth)
6084 {
6085     const struct wined3d_resource *resource = &surface->resource;
6086     IWineD3DDeviceImpl *device = resource->device;
6087     const struct blit_shader *blitter;
6088
6089     blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_FILL,
6090             NULL, 0, 0, NULL, rect, resource->usage, resource->pool, resource->format);
6091     if (!blitter)
6092     {
6093         FIXME("No blitter is capable of performing the requested depth fill operation.\n");
6094         return WINED3DERR_INVALIDCALL;
6095     }
6096
6097     return blitter->depth_fill(device, surface, rect, depth);
6098 }
6099
6100 static HRESULT wined3d_surface_depth_blt(IWineD3DSurfaceImpl *src_surface, const RECT *src_rect,
6101         IWineD3DSurfaceImpl *dst_surface, const RECT *dst_rect)
6102 {
6103     IWineD3DDeviceImpl *device = src_surface->resource.device;
6104
6105     if (!fbo_blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_DEPTH_BLIT,
6106             src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
6107             dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
6108         return WINED3DERR_INVALIDCALL;
6109
6110     wined3d_surface_depth_blt_fbo(device, src_surface, src_rect, dst_surface, dst_rect);
6111
6112     surface_modify_ds_location(dst_surface, SFLAG_DS_OFFSCREEN,
6113             dst_surface->ds_current_size.cx, dst_surface->ds_current_size.cy);
6114     surface_modify_location(dst_surface, SFLAG_INDRAWABLE, TRUE);
6115
6116     return WINED3D_OK;
6117 }
6118
6119 /* Do not call while under the GL lock. */
6120 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect,
6121         IWineD3DSurface *src_surface, const RECT *SrcRect, DWORD flags,
6122         const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter)
6123 {
6124     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
6125     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
6126     IWineD3DDeviceImpl *device = This->resource.device;
6127     DWORD src_ds_flags, dst_ds_flags;
6128
6129     TRACE("iface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6130             iface, wine_dbgstr_rect(DestRect), src_surface, wine_dbgstr_rect(SrcRect),
6131             flags, DDBltFx, debug_d3dtexturefiltertype(Filter));
6132     TRACE("Usage is %s.\n", debug_d3dusage(This->resource.usage));
6133
6134     if ((This->flags & SFLAG_LOCKED) || (src && (src->flags & SFLAG_LOCKED)))
6135     {
6136         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
6137         return WINEDDERR_SURFACEBUSY;
6138     }
6139
6140     dst_ds_flags = This->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
6141     if (src)
6142         src_ds_flags = src->resource.format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL);
6143     else
6144         src_ds_flags = 0;
6145
6146     if (src_ds_flags || dst_ds_flags)
6147     {
6148         if (flags & WINEDDBLT_DEPTHFILL)
6149         {
6150             float depth;
6151             RECT rect;
6152
6153             TRACE("Depth fill.\n");
6154
6155             surface_get_rect(This, DestRect, &rect);
6156
6157             if (!surface_convert_depth_to_float(This, DDBltFx->u5.dwFillDepth, &depth))
6158                 return WINED3DERR_INVALIDCALL;
6159
6160             if (SUCCEEDED(wined3d_surface_depth_fill(This, &rect, depth)))
6161                 return WINED3D_OK;
6162         }
6163         else
6164         {
6165             RECT src_rect, dst_rect;
6166
6167             /* Accessing depth / stencil surfaces is supposed to fail while in
6168              * a scene, except for fills, which seem to work. */
6169             if (device->inScene)
6170             {
6171                 WARN("Rejecting depth / stencil access while in scene.\n");
6172                 return WINED3DERR_INVALIDCALL;
6173             }
6174
6175             if (src_ds_flags != dst_ds_flags)
6176             {
6177                 WARN("Rejecting depth / stencil blit between incompatible formats.\n");
6178                 return WINED3DERR_INVALIDCALL;
6179             }
6180
6181             if (SrcRect && (SrcRect->top || SrcRect->left
6182                     || SrcRect->bottom != src->resource.height
6183                     || SrcRect->right != src->resource.width))
6184             {
6185                 WARN("Rejecting depth / stencil blit with invalid source rect %s.\n",
6186                         wine_dbgstr_rect(SrcRect));
6187                 return WINED3DERR_INVALIDCALL;
6188             }
6189
6190             if (DestRect && (DestRect->top || DestRect->left
6191                     || DestRect->bottom != This->resource.height
6192                     || DestRect->right != This->resource.width))
6193             {
6194                 WARN("Rejecting depth / stencil blit with invalid destination rect %s.\n",
6195                         wine_dbgstr_rect(SrcRect));
6196                 return WINED3DERR_INVALIDCALL;
6197             }
6198
6199             if (src->resource.height != This->resource.height
6200                     || src->resource.width != This->resource.width)
6201             {
6202                 WARN("Rejecting depth / stencil blit with mismatched surface sizes.\n");
6203                 return WINED3DERR_INVALIDCALL;
6204             }
6205
6206             surface_get_rect(src, SrcRect, &src_rect);
6207             surface_get_rect(This, DestRect, &dst_rect);
6208
6209             if (SUCCEEDED(wined3d_surface_depth_blt(src, &src_rect, This, &dst_rect)))
6210                 return WINED3D_OK;
6211         }
6212     }
6213
6214     /* Special cases for RenderTargets */
6215     if ((This->resource.usage & WINED3DUSAGE_RENDERTARGET)
6216             || (src && (src->resource.usage & WINED3DUSAGE_RENDERTARGET)))
6217     {
6218         if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(This, DestRect, src, SrcRect, flags, DDBltFx, Filter)))
6219             return WINED3D_OK;
6220     }
6221
6222     /* For the rest call the X11 surface implementation.
6223      * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
6224      * other Blts are rather rare. */
6225     return IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, src_surface, SrcRect, flags, DDBltFx, Filter);
6226 }
6227
6228 static HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
6229         IWineD3DSurface *src_surface, const RECT *rsrc, DWORD trans)
6230 {
6231     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
6232     IWineD3DSurfaceImpl *src = (IWineD3DSurfaceImpl *)src_surface;
6233     IWineD3DDeviceImpl *device = This->resource.device;
6234
6235     TRACE("iface %p, dst_x %u, dst_y %u, src_surface %p, src_rect %s, flags %#x.\n",
6236             iface, dstx, dsty, src_surface, wine_dbgstr_rect(rsrc), trans);
6237
6238     if ((This->flags & SFLAG_LOCKED) || (src->flags & SFLAG_LOCKED))
6239     {
6240         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
6241         return WINEDDERR_SURFACEBUSY;
6242     }
6243
6244     if (device->inScene && (This == device->depth_stencil || src == device->depth_stencil))
6245     {
6246         TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
6247         return WINED3DERR_INVALIDCALL;
6248     }
6249
6250     /* Special cases for RenderTargets */
6251     if ((This->resource.usage & WINED3DUSAGE_RENDERTARGET)
6252             || (src->resource.usage & WINED3DUSAGE_RENDERTARGET))
6253     {
6254
6255         RECT SrcRect, DstRect;
6256         DWORD flags = 0;
6257
6258         surface_get_rect(src, rsrc, &SrcRect);
6259
6260         DstRect.left = dstx;
6261         DstRect.top=dsty;
6262         DstRect.right = dstx + SrcRect.right - SrcRect.left;
6263         DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
6264
6265         /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
6266         if (trans & WINEDDBLTFAST_SRCCOLORKEY)
6267             flags |= WINEDDBLT_KEYSRC;
6268         if (trans & WINEDDBLTFAST_DESTCOLORKEY)
6269             flags |= WINEDDBLT_KEYDEST;
6270         if (trans & WINEDDBLTFAST_WAIT)
6271             flags |= WINEDDBLT_WAIT;
6272         if (trans & WINEDDBLTFAST_DONOTWAIT)
6273             flags |= WINEDDBLT_DONOTWAIT;
6274
6275         if (SUCCEEDED(IWineD3DSurfaceImpl_BltOverride(This,
6276                 &DstRect, src, &SrcRect, flags, NULL, WINED3DTEXF_POINT)))
6277             return WINED3D_OK;
6278     }
6279
6280     return IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, src_surface, rsrc, trans);
6281 }
6282
6283 /* GL locking is done by the caller */
6284 static void surface_depth_blt(IWineD3DSurfaceImpl *This, const struct wined3d_gl_info *gl_info,
6285         GLuint texture, GLsizei w, GLsizei h, GLenum target)
6286 {
6287     IWineD3DDeviceImpl *device = This->resource.device;
6288     GLint compare_mode = GL_NONE;
6289     struct blt_info info;
6290     GLint old_binding = 0;
6291     RECT rect;
6292
6293     glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
6294
6295     glDisable(GL_CULL_FACE);
6296     glDisable(GL_BLEND);
6297     glDisable(GL_ALPHA_TEST);
6298     glDisable(GL_SCISSOR_TEST);
6299     glDisable(GL_STENCIL_TEST);
6300     glEnable(GL_DEPTH_TEST);
6301     glDepthFunc(GL_ALWAYS);
6302     glDepthMask(GL_TRUE);
6303     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
6304     glViewport(0, This->pow2Height - h, w, h);
6305
6306     SetRect(&rect, 0, h, w, 0);
6307     surface_get_blt_info(target, &rect, This->pow2Width, This->pow2Height, &info);
6308     GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6309     glGetIntegerv(info.binding, &old_binding);
6310     glBindTexture(info.bind_target, texture);
6311     if (gl_info->supported[ARB_SHADOW])
6312     {
6313         glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
6314         if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
6315     }
6316
6317     device->shader_backend->shader_select_depth_blt(device->shader_priv,
6318             gl_info, info.tex_type, &This->ds_current_size);
6319
6320     glBegin(GL_TRIANGLE_STRIP);
6321     glTexCoord3fv(info.coords[0]);
6322     glVertex2f(-1.0f, -1.0f);
6323     glTexCoord3fv(info.coords[1]);
6324     glVertex2f(1.0f, -1.0f);
6325     glTexCoord3fv(info.coords[2]);
6326     glVertex2f(-1.0f, 1.0f);
6327     glTexCoord3fv(info.coords[3]);
6328     glVertex2f(1.0f, 1.0f);
6329     glEnd();
6330
6331     if (compare_mode != GL_NONE) glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
6332     glBindTexture(info.bind_target, old_binding);
6333
6334     glPopAttrib();
6335
6336     device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
6337 }
6338
6339 void surface_modify_ds_location(IWineD3DSurfaceImpl *surface,
6340         DWORD location, UINT w, UINT h)
6341 {
6342     TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
6343
6344     if (location & ~SFLAG_DS_LOCATIONS)
6345         FIXME("Invalid location (%#x) specified.\n", location);
6346
6347     surface->ds_current_size.cx = w;
6348     surface->ds_current_size.cy = h;
6349     surface->flags &= ~SFLAG_DS_LOCATIONS;
6350     surface->flags |= location;
6351 }
6352
6353 /* Context activation is done by the caller. */
6354 void surface_load_ds_location(IWineD3DSurfaceImpl *surface, struct wined3d_context *context, DWORD location)
6355 {
6356     IWineD3DDeviceImpl *device = surface->resource.device;
6357     const struct wined3d_gl_info *gl_info = context->gl_info;
6358     GLsizei w, h;
6359
6360     TRACE("surface %p, new location %#x.\n", surface, location);
6361
6362     /* TODO: Make this work for modes other than FBO */
6363     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
6364
6365     if (!(surface->flags & location))
6366     {
6367         w = surface->ds_current_size.cx;
6368         h = surface->ds_current_size.cy;
6369         surface->ds_current_size.cx = 0;
6370         surface->ds_current_size.cy = 0;
6371     }
6372     else
6373     {
6374         w = surface->resource.width;
6375         h = surface->resource.height;
6376     }
6377
6378     if (surface->ds_current_size.cx == surface->resource.width
6379             && surface->ds_current_size.cy == surface->resource.height)
6380     {
6381         TRACE("Location (%#x) is already up to date.\n", location);
6382         return;
6383     }
6384
6385     if (surface->current_renderbuffer)
6386     {
6387         FIXME("Not supported with fixed up depth stencil.\n");
6388         return;
6389     }
6390
6391     if (!(surface->flags & SFLAG_DS_LOCATIONS))
6392     {
6393         /* This mostly happens when a depth / stencil is used without being
6394          * cleared first. In principle we could upload from sysmem, or
6395          * explicitly clear before first usage. For the moment there don't
6396          * appear to be a lot of applications depending on this, so a FIXME
6397          * should do. */
6398         FIXME("No up to date depth stencil location.\n");
6399         surface->flags |= location;
6400         surface->ds_current_size.cx = surface->resource.width;
6401         surface->ds_current_size.cy = surface->resource.height;
6402         return;
6403     }
6404
6405     if (location == SFLAG_DS_OFFSCREEN)
6406     {
6407         GLint old_binding = 0;
6408         GLenum bind_target;
6409
6410         /* The render target is allowed to be smaller than the depth/stencil
6411          * buffer, so the onscreen depth/stencil buffer is potentially smaller
6412          * than the offscreen surface. Don't overwrite the offscreen surface
6413          * with undefined data. */
6414         w = min(w, context->swapchain->presentParms.BackBufferWidth);
6415         h = min(h, context->swapchain->presentParms.BackBufferHeight);
6416
6417         TRACE("Copying onscreen depth buffer to depth texture.\n");
6418
6419         ENTER_GL();
6420
6421         if (!device->depth_blt_texture)
6422         {
6423             glGenTextures(1, &device->depth_blt_texture);
6424         }
6425
6426         /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
6427          * directly on the FBO texture. That's because we need to flip. */
6428         context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
6429         if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
6430         {
6431             glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6432             bind_target = GL_TEXTURE_RECTANGLE_ARB;
6433         }
6434         else
6435         {
6436             glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6437             bind_target = GL_TEXTURE_2D;
6438         }
6439         glBindTexture(bind_target, device->depth_blt_texture);
6440         glCopyTexImage2D(bind_target, surface->texture_level, surface->resource.format->glInternal, 0, 0, w, h, 0);
6441         glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6442         glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6443         glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
6444         glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
6445         glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
6446         glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6447         glBindTexture(bind_target, old_binding);
6448
6449         /* Setup the destination */
6450         if (!device->depth_blt_rb)
6451         {
6452             gl_info->fbo_ops.glGenRenderbuffers(1, &device->depth_blt_rb);
6453             checkGLcall("glGenRenderbuffersEXT");
6454         }
6455         if (device->depth_blt_rb_w != w || device->depth_blt_rb_h != h)
6456         {
6457             gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, device->depth_blt_rb);
6458             checkGLcall("glBindRenderbufferEXT");
6459             gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, w, h);
6460             checkGLcall("glRenderbufferStorageEXT");
6461             device->depth_blt_rb_w = w;
6462             device->depth_blt_rb_h = h;
6463         }
6464
6465         context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
6466         gl_info->fbo_ops.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
6467                 GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, device->depth_blt_rb);
6468         checkGLcall("glFramebufferRenderbufferEXT");
6469         context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, surface, FALSE);
6470
6471         /* Do the actual blit */
6472         surface_depth_blt(surface, gl_info, device->depth_blt_texture, w, h, bind_target);
6473         checkGLcall("depth_blt");
6474
6475         if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
6476         else context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
6477
6478         LEAVE_GL();
6479
6480         if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
6481     }
6482     else if (location == SFLAG_DS_ONSCREEN)
6483     {
6484         TRACE("Copying depth texture to onscreen depth buffer.\n");
6485
6486         ENTER_GL();
6487
6488         context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
6489         surface_depth_blt(surface, gl_info, surface->texture_name,
6490                 w, h, surface->texture_target);
6491         checkGLcall("depth_blt");
6492
6493         if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
6494
6495         LEAVE_GL();
6496
6497         if (wined3d_settings.strict_draw_ordering) wglFlush(); /* Flush to ensure ordering across contexts. */
6498     }
6499     else
6500     {
6501         ERR("Invalid location (%#x) specified.\n", location);
6502     }
6503
6504     surface->flags |= location;
6505     surface->ds_current_size.cx = surface->resource.width;
6506     surface->ds_current_size.cy = surface->resource.height;
6507 }
6508
6509 void surface_modify_location(IWineD3DSurfaceImpl *surface, DWORD flag, BOOL persistent)
6510 {
6511     const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
6512     IWineD3DSurfaceImpl *overlay;
6513
6514     TRACE("surface %p, location %s, persistent %#x.\n",
6515             surface, debug_surflocation(flag), persistent);
6516
6517     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6518     {
6519         if (surface_is_offscreen(surface))
6520         {
6521             /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
6522             if (flag & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)) flag |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
6523         }
6524         else
6525         {
6526             TRACE("Surface %p is an onscreen surface.\n", surface);
6527         }
6528     }
6529
6530     if (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6531             && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6532     {
6533         flag |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6534     }
6535
6536     if (persistent)
6537     {
6538         if (((surface->flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE))
6539                 || ((surface->flags & SFLAG_INSRGBTEX) && !(flag & SFLAG_INSRGBTEX)))
6540         {
6541             if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6542             {
6543                 TRACE("Passing to container.\n");
6544                 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
6545             }
6546         }
6547         surface->flags &= ~SFLAG_LOCATIONS;
6548         surface->flags |= flag;
6549
6550         /* Redraw emulated overlays, if any */
6551         if (flag & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
6552         {
6553             LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, IWineD3DSurfaceImpl, overlay_entry)
6554             {
6555                 overlay->surface_ops->surface_draw_overlay(overlay);
6556             }
6557         }
6558     }
6559     else
6560     {
6561         if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
6562         {
6563             if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6564             {
6565                 TRACE("Passing to container\n");
6566                 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
6567             }
6568         }
6569         surface->flags &= ~flag;
6570     }
6571
6572     if (!(surface->flags & SFLAG_LOCATIONS))
6573     {
6574         ERR("Surface %p does not have any up to date location.\n", surface);
6575     }
6576 }
6577
6578 HRESULT surface_load_location(IWineD3DSurfaceImpl *surface, DWORD flag, const RECT *rect)
6579 {
6580     IWineD3DDeviceImpl *device = surface->resource.device;
6581     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6582     BOOL drawable_read_ok = surface_is_offscreen(surface);
6583     struct wined3d_format format;
6584     CONVERT_TYPES convert;
6585     int width, pitch, outpitch;
6586     BYTE *mem;
6587     BOOL in_fbo = FALSE;
6588
6589     TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(flag), wine_dbgstr_rect(rect));
6590
6591     if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6592     {
6593         if (flag == SFLAG_INTEXTURE)
6594         {
6595             struct wined3d_context *context = context_acquire(device, NULL);
6596             surface_load_ds_location(surface, context, SFLAG_DS_OFFSCREEN);
6597             context_release(context);
6598             return WINED3D_OK;
6599         }
6600         else
6601         {
6602             FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(flag));
6603             return WINED3DERR_INVALIDCALL;
6604         }
6605     }
6606
6607     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6608     {
6609         if (surface_is_offscreen(surface))
6610         {
6611             /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets.
6612              * Prefer SFLAG_INTEXTURE. */
6613             if (flag == SFLAG_INDRAWABLE) flag = SFLAG_INTEXTURE;
6614             drawable_read_ok = FALSE;
6615             in_fbo = TRUE;
6616         }
6617         else
6618         {
6619             TRACE("Surface %p is an onscreen surface.\n", surface);
6620         }
6621     }
6622
6623     if (flag == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6624     {
6625         flag = SFLAG_INTEXTURE;
6626     }
6627
6628     if (surface->flags & flag)
6629     {
6630         TRACE("Location already up to date\n");
6631         return WINED3D_OK;
6632     }
6633
6634     if (!(surface->flags & SFLAG_LOCATIONS))
6635     {
6636         ERR("Surface %p does not have any up to date location.\n", surface);
6637         surface->flags |= SFLAG_LOST;
6638         return WINED3DERR_DEVICELOST;
6639     }
6640
6641     if (flag == SFLAG_INSYSMEM)
6642     {
6643         surface_prepare_system_memory(surface);
6644
6645         /* Download the surface to system memory */
6646         if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
6647         {
6648             struct wined3d_context *context = NULL;
6649
6650             if (!device->isInDraw) context = context_acquire(device, NULL);
6651
6652             surface_bind_and_dirtify(surface, gl_info, !(surface->flags & SFLAG_INTEXTURE));
6653             surface_download_data(surface, gl_info);
6654
6655             if (context) context_release(context);
6656         }
6657         else
6658         {
6659             /* Note: It might be faster to download into a texture first. */
6660             read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
6661                     IWineD3DSurface_GetPitch((IWineD3DSurface *)surface));
6662         }
6663     }
6664     else if (flag == SFLAG_INDRAWABLE)
6665     {
6666         if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
6667             surface_load_location(surface, SFLAG_INTEXTURE, NULL);
6668
6669         if (surface->flags & SFLAG_INTEXTURE)
6670         {
6671             RECT r;
6672
6673             surface_get_rect(surface, rect, &r);
6674             surface_blt_to_drawable(device, WINED3DTEXF_POINT, FALSE, surface, &r, surface, &r);
6675         }
6676         else
6677         {
6678             int byte_count;
6679             if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
6680             {
6681                 /* This needs a shader to convert the srgb data sampled from the GL texture into RGB
6682                  * values, otherwise we get incorrect values in the target. For now go the slow way
6683                  * via a system memory copy
6684                  */
6685                 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6686             }
6687
6688             d3dfmt_get_conv(surface, FALSE /* We need color keying */,
6689                     FALSE /* We won't use textures */, &format, &convert);
6690
6691             /* The width is in 'length' not in bytes */
6692             width = surface->resource.width;
6693             pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);
6694
6695             /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
6696              * but it isn't set (yet) in all cases it is getting called. */
6697             if ((convert != NO_CONVERSION) && (surface->flags & SFLAG_PBO))
6698             {
6699                 struct wined3d_context *context = NULL;
6700
6701                 TRACE("Removing the pbo attached to surface %p.\n", surface);
6702
6703                 if (!device->isInDraw) context = context_acquire(device, NULL);
6704                 surface_remove_pbo(surface, gl_info);
6705                 if (context) context_release(context);
6706             }
6707
6708             if ((convert != NO_CONVERSION) && surface->resource.allocatedMemory)
6709             {
6710                 int height = surface->resource.height;
6711                 byte_count = format.conv_byte_count;
6712
6713                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6714                 outpitch = width * byte_count;
6715                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6716
6717                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
6718                 if(!mem) {
6719                     ERR("Out of memory %d, %d!\n", outpitch, height);
6720                     return WINED3DERR_OUTOFVIDEOMEMORY;
6721                 }
6722                 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, pitch,
6723                         width, height, outpitch, convert, surface);
6724
6725                 surface->flags |= SFLAG_CONVERTED;
6726             }
6727             else
6728             {
6729                 surface->flags &= ~SFLAG_CONVERTED;
6730                 mem = surface->resource.allocatedMemory;
6731                 byte_count = format.byte_count;
6732             }
6733
6734             flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6735
6736             /* Don't delete PBO memory */
6737             if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6738                 HeapFree(GetProcessHeap(), 0, mem);
6739         }
6740     }
6741     else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */
6742     {
6743         const DWORD attach_flags = WINED3DFMT_FLAG_FBO_ATTACHABLE | WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB;
6744
6745         if (drawable_read_ok && (surface->flags & SFLAG_INDRAWABLE))
6746         {
6747             read_from_framebuffer_texture(surface, flag == SFLAG_INSRGBTEX);
6748         }
6749         else if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6750                 && (surface->resource.format->flags & attach_flags) == attach_flags
6751                 && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6752                         NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6753                         NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6754         {
6755             DWORD src_location = flag == SFLAG_INSRGBTEX ? SFLAG_INTEXTURE : SFLAG_INSRGBTEX;
6756             RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6757
6758             surface_blt_fbo(surface->resource.device, WINED3DTEXF_POINT,
6759                     surface, src_location, &rect, surface, flag, &rect);
6760         }
6761         else
6762         {
6763             /* Upload from system memory */
6764             BOOL srgb = flag == SFLAG_INSRGBTEX;
6765             struct wined3d_context *context = NULL;
6766
6767             d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6768                     TRUE /* We will use textures */, &format, &convert);
6769
6770             if (srgb)
6771             {
6772                 if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6773                 {
6774                     /* Performance warning... */
6775                     FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6776                     surface_load_location(surface, SFLAG_INSYSMEM, rect);
6777                 }
6778             }
6779             else
6780             {
6781                 if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6782                 {
6783                     /* Performance warning... */
6784                     FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6785                     surface_load_location(surface, SFLAG_INSYSMEM, rect);
6786                 }
6787             }
6788             if (!(surface->flags & SFLAG_INSYSMEM))
6789             {
6790                 WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6791                 /* Lets hope we get it from somewhere... */
6792                 surface_load_location(surface, SFLAG_INSYSMEM, rect);
6793             }
6794
6795             if (!device->isInDraw) context = context_acquire(device, NULL);
6796
6797             surface_prepare_texture(surface, gl_info, srgb);
6798             surface_bind_and_dirtify(surface, gl_info, srgb);
6799
6800             if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6801             {
6802                 surface->flags |= SFLAG_GLCKEY;
6803                 surface->glCKey = surface->SrcBltCKey;
6804             }
6805             else surface->flags &= ~SFLAG_GLCKEY;
6806
6807             /* The width is in 'length' not in bytes */
6808             width = surface->resource.width;
6809             pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *)surface);
6810
6811             /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
6812              * but it isn't set (yet) in all cases it is getting called. */
6813             if ((convert != NO_CONVERSION || format.convert) && (surface->flags & SFLAG_PBO))
6814             {
6815                 TRACE("Removing the pbo attached to surface %p.\n", surface);
6816                 surface_remove_pbo(surface, gl_info);
6817             }
6818
6819             if (format.convert)
6820             {
6821                 /* This code is entered for texture formats which need a fixup. */
6822                 UINT height = surface->resource.height;
6823
6824                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6825                 outpitch = width * format.conv_byte_count;
6826                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6827
6828                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
6829                 if(!mem) {
6830                     ERR("Out of memory %d, %d!\n", outpitch, height);
6831                     if (context) context_release(context);
6832                     return WINED3DERR_OUTOFVIDEOMEMORY;
6833                 }
6834                 format.convert(surface->resource.allocatedMemory, mem, pitch, width, height);
6835             }
6836             else if (convert != NO_CONVERSION && surface->resource.allocatedMemory)
6837             {
6838                 /* This code is only entered for color keying fixups */
6839                 UINT height = surface->resource.height;
6840
6841                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6842                 outpitch = width * format.conv_byte_count;
6843                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6844
6845                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
6846                 if(!mem) {
6847                     ERR("Out of memory %d, %d!\n", outpitch, height);
6848                     if (context) context_release(context);
6849                     return WINED3DERR_OUTOFVIDEOMEMORY;
6850                 }
6851                 d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, pitch,
6852                         width, height, outpitch, convert, surface);
6853             }
6854             else
6855             {
6856                 mem = surface->resource.allocatedMemory;
6857             }
6858
6859             /* Make sure the correct pitch is used */
6860             ENTER_GL();
6861             glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
6862             LEAVE_GL();
6863
6864             if (mem || (surface->flags & SFLAG_PBO))
6865                 surface_upload_data(surface, gl_info, &format, srgb, mem);
6866
6867             /* Restore the default pitch */
6868             ENTER_GL();
6869             glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
6870             LEAVE_GL();
6871
6872             if (context) context_release(context);
6873
6874             /* Don't delete PBO memory */
6875             if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6876                 HeapFree(GetProcessHeap(), 0, mem);
6877         }
6878     }
6879
6880     if (!rect)
6881     {
6882         surface->flags |= flag;
6883
6884         if (flag != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6885             surface_evict_sysmem(surface);
6886     }
6887
6888     if (in_fbo && (surface->flags & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)))
6889     {
6890         /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
6891         surface->flags |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
6892     }
6893
6894     if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6895             && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6896     {
6897         surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6898     }
6899
6900     return WINED3D_OK;
6901 }
6902
6903 BOOL surface_is_offscreen(IWineD3DSurfaceImpl *surface)
6904 {
6905     struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
6906
6907     /* Not on a swapchain - must be offscreen */
6908     if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE;
6909
6910     /* The front buffer is always onscreen */
6911     if (surface == swapchain->front_buffer) return FALSE;
6912
6913     /* If the swapchain is rendered to an FBO, the backbuffer is
6914      * offscreen, otherwise onscreen */
6915     return swapchain->render_to_fbo;
6916 }
6917
6918 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
6919 {
6920     /* IUnknown */
6921     IWineD3DBaseSurfaceImpl_QueryInterface,
6922     IWineD3DBaseSurfaceImpl_AddRef,
6923     IWineD3DSurfaceImpl_Release,
6924     /* IWineD3DResource */
6925     IWineD3DBaseSurfaceImpl_GetParent,
6926     IWineD3DBaseSurfaceImpl_SetPrivateData,
6927     IWineD3DBaseSurfaceImpl_GetPrivateData,
6928     IWineD3DBaseSurfaceImpl_FreePrivateData,
6929     IWineD3DBaseSurfaceImpl_SetPriority,
6930     IWineD3DBaseSurfaceImpl_GetPriority,
6931     IWineD3DSurfaceImpl_PreLoad,
6932     /* IWineD3DSurface */
6933     IWineD3DBaseSurfaceImpl_GetResource,
6934     IWineD3DSurfaceImpl_Map,
6935     IWineD3DSurfaceImpl_Unmap,
6936     IWineD3DSurfaceImpl_GetDC,
6937     IWineD3DSurfaceImpl_ReleaseDC,
6938     IWineD3DSurfaceImpl_Flip,
6939     IWineD3DSurfaceImpl_Blt,
6940     IWineD3DBaseSurfaceImpl_GetBltStatus,
6941     IWineD3DBaseSurfaceImpl_GetFlipStatus,
6942     IWineD3DBaseSurfaceImpl_IsLost,
6943     IWineD3DBaseSurfaceImpl_Restore,
6944     IWineD3DSurfaceImpl_BltFast,
6945     IWineD3DBaseSurfaceImpl_GetPalette,
6946     IWineD3DBaseSurfaceImpl_SetPalette,
6947     IWineD3DBaseSurfaceImpl_SetColorKey,
6948     IWineD3DBaseSurfaceImpl_GetPitch,
6949     IWineD3DSurfaceImpl_SetMem,
6950     IWineD3DBaseSurfaceImpl_SetOverlayPosition,
6951     IWineD3DBaseSurfaceImpl_GetOverlayPosition,
6952     IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
6953     IWineD3DBaseSurfaceImpl_UpdateOverlay,
6954     IWineD3DBaseSurfaceImpl_SetClipper,
6955     IWineD3DBaseSurfaceImpl_GetClipper,
6956     /* Internal use: */
6957     IWineD3DSurfaceImpl_SetFormat,
6958 };
6959
6960 static HRESULT ffp_blit_alloc(IWineD3DDeviceImpl *device) { return WINED3D_OK; }
6961 /* Context activation is done by the caller. */
6962 static void ffp_blit_free(IWineD3DDeviceImpl *device) { }
6963
6964 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6965 /* Context activation is done by the caller. */
6966 static void ffp_blit_p8_upload_palette(IWineD3DSurfaceImpl *surface, const struct wined3d_gl_info *gl_info)
6967 {
6968     BYTE table[256][4];
6969     BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) ? TRUE : FALSE;
6970
6971     d3dfmt_p8_init_palette(surface, table, colorkey_active);
6972
6973     TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6974     ENTER_GL();
6975     GL_EXTCALL(glColorTableEXT(surface->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6976     LEAVE_GL();
6977 }
6978
6979 /* Context activation is done by the caller. */
6980 static HRESULT ffp_blit_set(void *blit_priv, const struct wined3d_gl_info *gl_info, IWineD3DSurfaceImpl *surface)
6981 {
6982     enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6983
6984     /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6985      * else the surface is converted in software at upload time in LoadLocation.
6986      */
6987     if(fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6988         ffp_blit_p8_upload_palette(surface, gl_info);
6989
6990     ENTER_GL();
6991     glEnable(surface->texture_target);
6992     checkGLcall("glEnable(surface->texture_target)");
6993     LEAVE_GL();
6994     return WINED3D_OK;
6995 }
6996
6997 /* Context activation is done by the caller. */
6998 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
6999 {
7000     ENTER_GL();
7001     glDisable(GL_TEXTURE_2D);
7002     checkGLcall("glDisable(GL_TEXTURE_2D)");
7003     if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
7004     {
7005         glDisable(GL_TEXTURE_CUBE_MAP_ARB);
7006         checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
7007     }
7008     if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
7009     {
7010         glDisable(GL_TEXTURE_RECTANGLE_ARB);
7011         checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
7012     }
7013     LEAVE_GL();
7014 }
7015
7016 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
7017         const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
7018         const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format)
7019 {
7020     enum complex_fixup src_fixup;
7021
7022     switch (blit_op)
7023     {
7024         case WINED3D_BLIT_OP_COLOR_BLIT:
7025             src_fixup = get_complex_fixup(src_format->color_fixup);
7026             if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
7027             {
7028                 TRACE("Checking support for fixup:\n");
7029                 dump_color_fixup_desc(src_format->color_fixup);
7030             }
7031
7032             if (!is_identity_fixup(dst_format->color_fixup))
7033             {
7034                 TRACE("Destination fixups are not supported\n");
7035                 return FALSE;
7036             }
7037
7038             if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
7039             {
7040                 TRACE("P8 fixup supported\n");
7041                 return TRUE;
7042             }
7043
7044             /* We only support identity conversions. */
7045             if (is_identity_fixup(src_format->color_fixup))
7046             {
7047                 TRACE("[OK]\n");
7048                 return TRUE;
7049             }
7050
7051             TRACE("[FAILED]\n");
7052             return FALSE;
7053
7054         case WINED3D_BLIT_OP_COLOR_FILL:
7055             if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
7056             {
7057                 TRACE("Color fill not supported\n");
7058                 return FALSE;
7059             }
7060
7061             return TRUE;
7062
7063         case WINED3D_BLIT_OP_DEPTH_FILL:
7064             return TRUE;
7065
7066         default:
7067             TRACE("Unsupported blit_op=%d\n", blit_op);
7068             return FALSE;
7069     }
7070 }
7071
7072 /* Do not call while under the GL lock. */
7073 static HRESULT ffp_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface,
7074         const RECT *dst_rect, const WINED3DCOLORVALUE *color)
7075 {
7076     const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
7077
7078     return device_clear_render_targets(device, 1, &dst_surface, NULL,
7079             1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
7080 }
7081
7082 /* Do not call while under the GL lock. */
7083 static HRESULT ffp_blit_depth_fill(IWineD3DDeviceImpl *device,
7084         IWineD3DSurfaceImpl *surface, const RECT *rect, float depth)
7085 {
7086     const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
7087
7088     return device_clear_render_targets(device, 0, NULL, surface,
7089             1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
7090 }
7091
7092 const struct blit_shader ffp_blit =  {
7093     ffp_blit_alloc,
7094     ffp_blit_free,
7095     ffp_blit_set,
7096     ffp_blit_unset,
7097     ffp_blit_supported,
7098     ffp_blit_color_fill,
7099     ffp_blit_depth_fill,
7100 };
7101
7102 static HRESULT cpu_blit_alloc(IWineD3DDeviceImpl *device)
7103 {
7104     return WINED3D_OK;
7105 }
7106
7107 /* Context activation is done by the caller. */
7108 static void cpu_blit_free(IWineD3DDeviceImpl *device)
7109 {
7110 }
7111
7112 /* Context activation is done by the caller. */
7113 static HRESULT cpu_blit_set(void *blit_priv, const struct wined3d_gl_info *gl_info, IWineD3DSurfaceImpl *surface)
7114 {
7115     return WINED3D_OK;
7116 }
7117
7118 /* Context activation is done by the caller. */
7119 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
7120 {
7121 }
7122
7123 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
7124         const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
7125         const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format)
7126 {
7127     if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
7128     {
7129         return TRUE;
7130     }
7131
7132     return FALSE;
7133 }
7134
7135 /* Do not call while under the GL lock. */
7136 static HRESULT cpu_blit_color_fill(IWineD3DDeviceImpl *device, IWineD3DSurfaceImpl *dst_surface,
7137         const RECT *dst_rect, const WINED3DCOLORVALUE *color)
7138 {
7139     WINEDDBLTFX BltFx;
7140
7141     memset(&BltFx, 0, sizeof(BltFx));
7142     BltFx.dwSize = sizeof(BltFx);
7143     BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface->resource.format, color);
7144     return IWineD3DBaseSurfaceImpl_Blt((IWineD3DSurface*)dst_surface, dst_rect,
7145             NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_POINT);
7146 }
7147
7148 /* Do not call while under the GL lock. */
7149 static HRESULT cpu_blit_depth_fill(IWineD3DDeviceImpl *device,
7150         IWineD3DSurfaceImpl *surface, const RECT *rect, float depth)
7151 {
7152     FIXME("Depth filling not implemented by cpu_blit.\n");
7153     return WINED3DERR_INVALIDCALL;
7154 }
7155
7156 const struct blit_shader cpu_blit =  {
7157     cpu_blit_alloc,
7158     cpu_blit_free,
7159     cpu_blit_set,
7160     cpu_blit_unset,
7161     cpu_blit_supported,
7162     cpu_blit_color_fill,
7163     cpu_blit_depth_fill,
7164 };
7165
7166 static BOOL fbo_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
7167         const RECT *src_rect, DWORD src_usage, WINED3DPOOL src_pool, const struct wined3d_format *src_format,
7168         const RECT *dst_rect, DWORD dst_usage, WINED3DPOOL dst_pool, const struct wined3d_format *dst_format)
7169 {
7170     if ((wined3d_settings.offscreen_rendering_mode != ORM_FBO) || !gl_info->fbo_ops.glBlitFramebuffer)
7171         return FALSE;
7172
7173     /* Source and/or destination need to be on the GL side */
7174     if (src_pool == WINED3DPOOL_SYSTEMMEM || dst_pool == WINED3DPOOL_SYSTEMMEM)
7175         return FALSE;
7176
7177     switch (blit_op)
7178     {
7179         case WINED3D_BLIT_OP_COLOR_BLIT:
7180             if (!((src_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (src_usage & WINED3DUSAGE_RENDERTARGET)))
7181                 return FALSE;
7182             if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
7183                 return FALSE;
7184             break;
7185
7186         case WINED3D_BLIT_OP_DEPTH_BLIT:
7187             if (!(src_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
7188                 return FALSE;
7189             if (!(dst_format->flags & (WINED3DFMT_FLAG_DEPTH | WINED3DFMT_FLAG_STENCIL)))
7190                 return FALSE;
7191             break;
7192
7193         default:
7194             return FALSE;
7195     }
7196
7197     if (!(src_format->id == dst_format->id
7198             || (is_identity_fixup(src_format->color_fixup)
7199             && is_identity_fixup(dst_format->color_fixup))))
7200         return FALSE;
7201
7202     return TRUE;
7203 }
7204
7205 static ULONG WINAPI IWineGDISurfaceImpl_Release(IWineD3DSurface *iface)
7206 {
7207     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7208     ULONG refcount;
7209
7210     TRACE("Surface %p, container %p of type %#x.\n",
7211             surface, surface->container.u.base, surface->container.type);
7212
7213     switch (surface->container.type)
7214     {
7215         case WINED3D_CONTAINER_TEXTURE:
7216             return wined3d_texture_decref(surface->container.u.texture);
7217
7218         case WINED3D_CONTAINER_SWAPCHAIN:
7219             return wined3d_swapchain_decref(surface->container.u.swapchain);
7220
7221         default:
7222             ERR("Unhandled container type %#x.\n", surface->container.type);
7223         case WINED3D_CONTAINER_NONE:
7224             break;
7225     }
7226
7227     refcount = InterlockedDecrement(&surface->resource.ref);
7228     TRACE("%p decreasing refcount to %u.\n", surface, refcount);
7229
7230     if (!refcount)
7231     {
7232         surface_gdi_cleanup(surface);
7233         surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
7234
7235         TRACE("Destroyed surface %p.\n", surface);
7236         HeapFree(GetProcessHeap(), 0, surface);
7237     }
7238
7239     return refcount;
7240 }
7241
7242 static void WINAPI IWineGDISurfaceImpl_PreLoad(IWineD3DSurface *iface)
7243 {
7244     ERR("(%p): PreLoad is not supported on X11 surfaces!\n", iface);
7245     ERR("(%p): Most likely the parent library did something wrong.\n", iface);
7246     ERR("(%p): Please report to wine-devel\n", iface);
7247 }
7248
7249 static HRESULT WINAPI IWineGDISurfaceImpl_Map(IWineD3DSurface *iface,
7250         WINED3DLOCKED_RECT *locked_rect, const RECT *rect, DWORD flags)
7251 {
7252     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7253
7254     TRACE("iface %p, locked_rect %p, rect %s, flags %#x.\n",
7255             iface, locked_rect, wine_dbgstr_rect(rect), flags);
7256
7257     /* Already locked? */
7258     if (surface->flags & SFLAG_LOCKED)
7259     {
7260         WARN("Surface already mapped.\n");
7261         /* What should I return here? */
7262         return WINED3DERR_INVALIDCALL;
7263     }
7264     surface->flags |= SFLAG_LOCKED;
7265
7266     if (!surface->resource.allocatedMemory)
7267     {
7268         /* This happens on gdi surfaces if the application set a user pointer
7269          * and resets it. Recreate the DIB section. */
7270         surface_create_dib_section(surface);
7271         surface->resource.allocatedMemory = surface->dib.bitmap_data;
7272     }
7273
7274     return IWineD3DBaseSurfaceImpl_Map(iface, locked_rect, rect, flags);
7275 }
7276
7277 static HRESULT WINAPI IWineGDISurfaceImpl_Unmap(IWineD3DSurface *iface)
7278 {
7279     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7280
7281     TRACE("iface %p.\n", iface);
7282
7283     if (!(surface->flags & SFLAG_LOCKED))
7284     {
7285         WARN("Trying to unmap unmapped surface.\n");
7286         return WINEDDERR_NOTLOCKED;
7287     }
7288
7289     /* Tell the swapchain to update the screen. */
7290     if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
7291     {
7292         struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
7293         if (surface == swapchain->front_buffer)
7294         {
7295             x11_copy_to_screen(swapchain, &surface->lockedRect);
7296         }
7297     }
7298
7299     surface->flags &= ~SFLAG_LOCKED;
7300     memset(&surface->lockedRect, 0, sizeof(RECT));
7301
7302     return WINED3D_OK;
7303 }
7304
7305 /*****************************************************************************
7306  * IWineD3DSurface::Flip, GDI version
7307  *
7308  * Flips 2 flipping enabled surfaces. Determining the 2 targets is done by
7309  * the parent library. This implementation changes the data pointers of the
7310  * surfaces and copies the new front buffer content to the screen
7311  *
7312  * Params:
7313  *  override: Flipping target(e.g. back buffer)
7314  *
7315  * Returns:
7316  *  WINED3D_OK on success
7317  *
7318  *****************************************************************************/
7319 static HRESULT WINAPI IWineGDISurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD flags)
7320 {
7321     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7322     struct wined3d_swapchain *swapchain;
7323     HRESULT hr;
7324
7325     if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
7326     {
7327         ERR("Flipped surface is not on a swapchain\n");
7328         return WINEDDERR_NOTFLIPPABLE;
7329     }
7330
7331     swapchain = surface->container.u.swapchain;
7332     hr = wined3d_swapchain_present(swapchain, NULL, NULL, swapchain->win_handle, NULL, 0);
7333
7334     return hr;
7335 }
7336
7337 static HRESULT WINAPI IWineGDISurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *dc)
7338 {
7339     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7340     WINED3DLOCKED_RECT lock;
7341     HRESULT hr;
7342     RGBQUAD col[256];
7343
7344     TRACE("iface %p, dc %p.\n", iface, dc);
7345
7346     if (!(surface->flags & SFLAG_DIBSECTION))
7347     {
7348         WARN("DC not supported on this surface\n");
7349         return WINED3DERR_INVALIDCALL;
7350     }
7351
7352     if (surface->flags & SFLAG_USERPTR)
7353     {
7354         ERR("Not supported on surfaces with application-provided memory.\n");
7355         return WINEDDERR_NODC;
7356     }
7357
7358     /* Give more detailed info for ddraw. */
7359     if (surface->flags & SFLAG_DCINUSE)
7360         return WINEDDERR_DCALREADYCREATED;
7361
7362     /* Can't GetDC if the surface is locked. */
7363     if (surface->flags & SFLAG_LOCKED)
7364         return WINED3DERR_INVALIDCALL;
7365
7366     memset(&lock, 0, sizeof(lock)); /* To be sure */
7367
7368     /* Should have a DIB section already. */
7369
7370     /* Map the surface. */
7371     hr = IWineD3DSurface_Map(iface, &lock, NULL, 0);
7372     if (FAILED(hr))
7373     {
7374         ERR("IWineD3DSurface_Map failed, hr %#x.\n", hr);
7375         /* keep the dib section */
7376         return hr;
7377     }
7378
7379     if (surface->resource.format->id == WINED3DFMT_P8_UINT
7380             || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
7381     {
7382         const PALETTEENTRY *pal = NULL;
7383
7384         if (surface->palette)
7385         {
7386             pal = surface->palette->palents;
7387         }
7388         else
7389         {
7390             struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
7391             IWineD3DSurfaceImpl *dds_primary = swapchain->front_buffer;
7392
7393             if (dds_primary && dds_primary->palette)
7394                 pal = dds_primary->palette->palents;
7395         }
7396
7397         if (pal)
7398         {
7399             unsigned int i;
7400
7401             for (i = 0; i < 256; ++i)
7402             {
7403                 col[i].rgbRed = pal[i].peRed;
7404                 col[i].rgbGreen = pal[i].peGreen;
7405                 col[i].rgbBlue = pal[i].peBlue;
7406                 col[i].rgbReserved = 0;
7407             }
7408             SetDIBColorTable(surface->hDC, 0, 256, col);
7409         }
7410     }
7411
7412     surface->flags |= SFLAG_DCINUSE;
7413
7414     *dc = surface->hDC;
7415     TRACE("Returning dc %p.\n", *dc);
7416
7417     return WINED3D_OK;
7418 }
7419
7420 static HRESULT WINAPI IWineGDISurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC dc)
7421 {
7422     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7423
7424     TRACE("iface %p, dc %p.\n", iface, dc);
7425
7426     if (!(surface->flags & SFLAG_DCINUSE))
7427         return WINEDDERR_NODC;
7428
7429     if (surface->hDC != dc)
7430     {
7431         WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
7432                 dc, surface->hDC);
7433         return WINEDDERR_NODC;
7434     }
7435
7436     /* We locked first, so unlock now. */
7437     IWineD3DSurface_Unmap(iface);
7438
7439     surface->flags &= ~SFLAG_DCINUSE;
7440
7441     return WINED3D_OK;
7442 }
7443
7444 static HRESULT WINAPI IWineGDISurfaceImpl_SetMem(IWineD3DSurface *iface, void *mem)
7445 {
7446     IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *)iface;
7447
7448     /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
7449     if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
7450     {
7451         ERR("Not supported on render targets.\n");
7452         return WINED3DERR_INVALIDCALL;
7453     }
7454
7455     if (surface->flags & (SFLAG_LOCKED | SFLAG_DCINUSE))
7456     {
7457         WARN("Surface is locked or the DC is in use.\n");
7458         return WINED3DERR_INVALIDCALL;
7459     }
7460
7461     if (mem && mem != surface->resource.allocatedMemory)
7462     {
7463         void *release = NULL;
7464
7465         /* Do I have to copy the old surface content? */
7466         if (surface->flags & SFLAG_DIBSECTION)
7467         {
7468             SelectObject(surface->hDC, surface->dib.holdbitmap);
7469             DeleteDC(surface->hDC);
7470             /* Release the DIB section. */
7471             DeleteObject(surface->dib.DIBsection);
7472             surface->dib.bitmap_data = NULL;
7473             surface->resource.allocatedMemory = NULL;
7474             surface->hDC = NULL;
7475             surface->flags &= ~SFLAG_DIBSECTION;
7476         }
7477         else if (!(surface->flags & SFLAG_USERPTR))
7478         {
7479             release = surface->resource.allocatedMemory;
7480         }
7481         surface->resource.allocatedMemory = mem;
7482         surface->flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
7483
7484         /* Now free the old memory, if any. */
7485         HeapFree(GetProcessHeap(), 0, release);
7486     }
7487     else if (surface->flags & SFLAG_USERPTR)
7488     {
7489         /* Map() and GetDC() will re-create the dib section and allocated memory. */
7490         surface->resource.allocatedMemory = NULL;
7491         surface->flags &= ~SFLAG_USERPTR;
7492     }
7493
7494     return WINED3D_OK;
7495 }
7496
7497 static const IWineD3DSurfaceVtbl IWineGDISurface_Vtbl =
7498 {
7499     /* IUnknown */
7500     IWineD3DBaseSurfaceImpl_QueryInterface,
7501     IWineD3DBaseSurfaceImpl_AddRef,
7502     IWineGDISurfaceImpl_Release,
7503     /* IWineD3DResource */
7504     IWineD3DBaseSurfaceImpl_GetParent,
7505     IWineD3DBaseSurfaceImpl_SetPrivateData,
7506     IWineD3DBaseSurfaceImpl_GetPrivateData,
7507     IWineD3DBaseSurfaceImpl_FreePrivateData,
7508     IWineD3DBaseSurfaceImpl_SetPriority,
7509     IWineD3DBaseSurfaceImpl_GetPriority,
7510     IWineGDISurfaceImpl_PreLoad,
7511     /* IWineD3DSurface */
7512     IWineD3DBaseSurfaceImpl_GetResource,
7513     IWineGDISurfaceImpl_Map,
7514     IWineGDISurfaceImpl_Unmap,
7515     IWineGDISurfaceImpl_GetDC,
7516     IWineGDISurfaceImpl_ReleaseDC,
7517     IWineGDISurfaceImpl_Flip,
7518     IWineD3DBaseSurfaceImpl_Blt,
7519     IWineD3DBaseSurfaceImpl_GetBltStatus,
7520     IWineD3DBaseSurfaceImpl_GetFlipStatus,
7521     IWineD3DBaseSurfaceImpl_IsLost,
7522     IWineD3DBaseSurfaceImpl_Restore,
7523     IWineD3DBaseSurfaceImpl_BltFast,
7524     IWineD3DBaseSurfaceImpl_GetPalette,
7525     IWineD3DBaseSurfaceImpl_SetPalette,
7526     IWineD3DBaseSurfaceImpl_SetColorKey,
7527     IWineD3DBaseSurfaceImpl_GetPitch,
7528     IWineGDISurfaceImpl_SetMem,
7529     IWineD3DBaseSurfaceImpl_SetOverlayPosition,
7530     IWineD3DBaseSurfaceImpl_GetOverlayPosition,
7531     IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
7532     IWineD3DBaseSurfaceImpl_UpdateOverlay,
7533     IWineD3DBaseSurfaceImpl_SetClipper,
7534     IWineD3DBaseSurfaceImpl_GetClipper,
7535     /* Internal use: */
7536     IWineD3DBaseSurfaceImpl_SetFormat,
7537 };
7538
7539 HRESULT surface_init(IWineD3DSurfaceImpl *surface, WINED3DSURFTYPE surface_type, UINT alignment,
7540         UINT width, UINT height, UINT level, BOOL lockable, BOOL discard, WINED3DMULTISAMPLE_TYPE multisample_type,
7541         UINT multisample_quality, IWineD3DDeviceImpl *device, DWORD usage, enum wined3d_format_id format_id,
7542         WINED3DPOOL pool, void *parent, const struct wined3d_parent_ops *parent_ops)
7543 {
7544     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7545     const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7546     void (*cleanup)(IWineD3DSurfaceImpl *This);
7547     unsigned int resource_size;
7548     HRESULT hr;
7549
7550     if (multisample_quality > 0)
7551     {
7552         FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7553         multisample_quality = 0;
7554     }
7555
7556     /* Quick lockable sanity check.
7557      * TODO: remove this after surfaces, usage and lockability have been debugged properly
7558      * this function is too deep to need to care about things like this.
7559      * Levels need to be checked too, since they all affect what can be done. */
7560     switch (pool)
7561     {
7562         case WINED3DPOOL_SCRATCH:
7563             if (!lockable)
7564             {
7565                 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7566                         "which are mutually exclusive, setting lockable to TRUE.\n");
7567                 lockable = TRUE;
7568             }
7569             break;
7570
7571         case WINED3DPOOL_SYSTEMMEM:
7572             if (!lockable)
7573                 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7574             break;
7575
7576         case WINED3DPOOL_MANAGED:
7577             if (usage & WINED3DUSAGE_DYNAMIC)
7578                 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7579             break;
7580
7581         case WINED3DPOOL_DEFAULT:
7582             if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7583                 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7584             break;
7585
7586         default:
7587             FIXME("Unknown pool %#x.\n", pool);
7588             break;
7589     };
7590
7591     if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3DPOOL_DEFAULT)
7592         FIXME("Trying to create a render target that isn't in the default pool.\n");
7593
7594     /* FIXME: Check that the format is supported by the device. */
7595
7596     resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7597     if (!resource_size)
7598         return WINED3DERR_INVALIDCALL;
7599
7600     surface->surface_type = surface_type;
7601
7602     /* Look at the implementation and set the correct Vtable. */
7603     switch (surface_type)
7604     {
7605         case SURFACE_OPENGL:
7606             surface->lpVtbl = &IWineD3DSurface_Vtbl;
7607             surface->surface_ops = &surface_ops;
7608             cleanup = surface_cleanup;
7609             break;
7610
7611         case SURFACE_GDI:
7612             surface->lpVtbl = &IWineGDISurface_Vtbl;
7613             surface->surface_ops = &gdi_surface_ops;
7614             cleanup = surface_gdi_cleanup;
7615             break;
7616
7617         default:
7618             ERR("Requested unknown surface implementation %#x.\n", surface_type);
7619             return WINED3DERR_INVALIDCALL;
7620     }
7621
7622     hr = resource_init(&surface->resource, device, WINED3DRTYPE_SURFACE, format,
7623             multisample_type, multisample_quality, usage, pool, width, height, 1,
7624             resource_size, parent, parent_ops, &surface_resource_ops);
7625     if (FAILED(hr))
7626     {
7627         WARN("Failed to initialize resource, returning %#x.\n", hr);
7628         return hr;
7629     }
7630
7631     /* "Standalone" surface. */
7632     surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
7633
7634     surface->texture_level = level;
7635     list_init(&surface->overlays);
7636
7637     /* Flags */
7638     surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7639     if (discard)
7640         surface->flags |= SFLAG_DISCARD;
7641     if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7642         surface->flags |= SFLAG_LOCKABLE;
7643
7644     /* Mark the texture as dirty so that it gets loaded first time around. */
7645     surface_add_dirty_rect(surface, NULL);
7646     list_init(&surface->renderbuffers);
7647
7648     TRACE("surface %p, memory %p, size %u\n",
7649             surface, surface->resource.allocatedMemory, surface->resource.size);
7650
7651     /* Call the private setup routine */
7652     hr = surface->surface_ops->surface_private_setup(surface);
7653     if (FAILED(hr))
7654     {
7655         ERR("Private setup failed, returning %#x\n", hr);
7656         cleanup(surface);
7657         return hr;
7658     }
7659
7660     return hr;
7661 }