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