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