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