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