ddraw: Avoid LPDIRECT3DDEVICE7.
[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, GLint level)
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->texture_level = level;
2124     surface_force_reload(surface);
2125 }
2126
2127 /* This call just downloads data, the caller is responsible for binding the
2128  * correct texture. */
2129 /* Context activation is done by the caller. */
2130 static void surface_download_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
2131 {
2132     const struct wined3d_format *format = surface->resource.format;
2133
2134     /* Only support read back of converted P8 surfaces. */
2135     if (surface->flags & SFLAG_CONVERTED && format->id != WINED3DFMT_P8_UINT)
2136     {
2137         ERR("Trying to read back converted surface %p with format %s.\n", surface, debug_d3dformat(format->id));
2138         return;
2139     }
2140
2141     ENTER_GL();
2142
2143     if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2144     {
2145         TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
2146                 surface, surface->texture_level, format->glFormat, format->glType,
2147                 surface->resource.allocatedMemory);
2148
2149         if (surface->flags & SFLAG_PBO)
2150         {
2151             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2152             checkGLcall("glBindBufferARB");
2153             GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target, surface->texture_level, NULL));
2154             checkGLcall("glGetCompressedTexImageARB");
2155             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2156             checkGLcall("glBindBufferARB");
2157         }
2158         else
2159         {
2160             GL_EXTCALL(glGetCompressedTexImageARB(surface->texture_target,
2161                     surface->texture_level, surface->resource.allocatedMemory));
2162             checkGLcall("glGetCompressedTexImageARB");
2163         }
2164
2165         LEAVE_GL();
2166     }
2167     else
2168     {
2169         void *mem;
2170         GLenum gl_format = format->glFormat;
2171         GLenum gl_type = format->glType;
2172         int src_pitch = 0;
2173         int dst_pitch = 0;
2174
2175         /* In case of P8 the index is stored in the alpha component if the primary render target uses P8. */
2176         if (format->id == WINED3DFMT_P8_UINT && primary_render_target_is_p8(surface->resource.device))
2177         {
2178             gl_format = GL_ALPHA;
2179             gl_type = GL_UNSIGNED_BYTE;
2180         }
2181
2182         if (surface->flags & SFLAG_NONPOW2)
2183         {
2184             unsigned char alignment = surface->resource.device->surface_alignment;
2185             src_pitch = format->byte_count * surface->pow2Width;
2186             dst_pitch = wined3d_surface_get_pitch(surface);
2187             src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
2188             mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * surface->pow2Height);
2189         }
2190         else
2191         {
2192             mem = surface->resource.allocatedMemory;
2193         }
2194
2195         TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
2196                 surface, surface->texture_level, gl_format, gl_type, mem);
2197
2198         if (surface->flags & SFLAG_PBO)
2199         {
2200             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
2201             checkGLcall("glBindBufferARB");
2202
2203             gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2204                     gl_format, gl_type, NULL);
2205             checkGLcall("glGetTexImage");
2206
2207             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
2208             checkGLcall("glBindBufferARB");
2209         }
2210         else
2211         {
2212             gl_info->gl_ops.gl.p_glGetTexImage(surface->texture_target, surface->texture_level,
2213                     gl_format, gl_type, mem);
2214             checkGLcall("glGetTexImage");
2215         }
2216         LEAVE_GL();
2217
2218         if (surface->flags & SFLAG_NONPOW2)
2219         {
2220             const BYTE *src_data;
2221             BYTE *dst_data;
2222             UINT y;
2223             /*
2224              * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
2225              * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
2226              * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
2227              *
2228              * We're doing this...
2229              *
2230              * instead of boxing the texture :
2231              * |<-texture width ->|  -->pow2width|   /\
2232              * |111111111111111111|              |   |
2233              * |222 Texture 222222| boxed empty  | texture height
2234              * |3333 Data 33333333|              |   |
2235              * |444444444444444444|              |   \/
2236              * -----------------------------------   |
2237              * |     boxed  empty | boxed empty  | pow2height
2238              * |                  |              |   \/
2239              * -----------------------------------
2240              *
2241              *
2242              * we're repacking the data to the expected texture width
2243              *
2244              * |<-texture width ->|  -->pow2width|   /\
2245              * |111111111111111111222222222222222|   |
2246              * |222333333333333333333444444444444| texture height
2247              * |444444                           |   |
2248              * |                                 |   \/
2249              * |                                 |   |
2250              * |            empty                | pow2height
2251              * |                                 |   \/
2252              * -----------------------------------
2253              *
2254              * == is the same as
2255              *
2256              * |<-texture width ->|    /\
2257              * |111111111111111111|
2258              * |222222222222222222|texture height
2259              * |333333333333333333|
2260              * |444444444444444444|    \/
2261              * --------------------
2262              *
2263              * this also means that any references to allocatedMemory should work with the data as if were a
2264              * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
2265              *
2266              * internally the texture is still stored in a boxed format so any references to textureName will
2267              * get a boxed texture with width pow2width and not a texture of width resource.width.
2268              *
2269              * Performance should not be an issue, because applications normally do not lock the surfaces when
2270              * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
2271              * and doesn't have to be re-read. */
2272             src_data = mem;
2273             dst_data = surface->resource.allocatedMemory;
2274             TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", surface, src_pitch, dst_pitch);
2275             for (y = 1; y < surface->resource.height; ++y)
2276             {
2277                 /* skip the first row */
2278                 src_data += src_pitch;
2279                 dst_data += dst_pitch;
2280                 memcpy(dst_data, src_data, dst_pitch);
2281             }
2282
2283             HeapFree(GetProcessHeap(), 0, mem);
2284         }
2285     }
2286
2287     /* Surface has now been downloaded */
2288     surface->flags |= SFLAG_INSYSMEM;
2289 }
2290
2291 /* This call just uploads data, the caller is responsible for binding the
2292  * correct texture. */
2293 /* Context activation is done by the caller. */
2294 static void surface_upload_data(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2295         const struct wined3d_format *format, const RECT *src_rect, UINT src_pitch, const POINT *dst_point,
2296         BOOL srgb, const struct wined3d_bo_address *data)
2297 {
2298     UINT update_w = src_rect->right - src_rect->left;
2299     UINT update_h = src_rect->bottom - src_rect->top;
2300
2301     TRACE("surface %p, gl_info %p, format %s, src_rect %s, src_pitch %u, dst_point %s, srgb %#x, data {%#x:%p}.\n",
2302             surface, gl_info, debug_d3dformat(format->id), wine_dbgstr_rect(src_rect), src_pitch,
2303             wine_dbgstr_point(dst_point), srgb, data->buffer_object, data->addr);
2304
2305     if (surface->resource.map_count)
2306     {
2307         WARN("Uploading a surface that is currently mapped, setting SFLAG_PIN_SYSMEM.\n");
2308         surface->flags |= SFLAG_PIN_SYSMEM;
2309     }
2310
2311     if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2312     {
2313         update_h *= format->height_scale.numerator;
2314         update_h /= format->height_scale.denominator;
2315     }
2316
2317     ENTER_GL();
2318
2319     if (data->buffer_object)
2320     {
2321         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, data->buffer_object));
2322         checkGLcall("glBindBufferARB");
2323     }
2324
2325     if (format->flags & WINED3DFMT_FLAG_COMPRESSED)
2326     {
2327         UINT row_length = wined3d_format_calculate_size(format, 1, update_w, 1);
2328         UINT row_count = (update_h + format->block_height - 1) / format->block_height;
2329         const BYTE *addr = data->addr;
2330         GLenum internal;
2331
2332         addr += (src_rect->top / format->block_height) * src_pitch;
2333         addr += (src_rect->left / format->block_width) * format->block_byte_count;
2334
2335         if (srgb)
2336             internal = format->glGammaInternal;
2337         else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2338             internal = format->rtInternal;
2339         else
2340             internal = format->glInternal;
2341
2342         TRACE("glCompressedTexSubImage2DARB, target %#x, level %d, x %d, y %d, w %d, h %d, "
2343                 "format %#x, image_size %#x, addr %p.\n", surface->texture_target, surface->texture_level,
2344                 dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr);
2345
2346         if (row_length == src_pitch)
2347         {
2348             GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2349                     dst_point->x, dst_point->y, update_w, update_h, internal, row_count * row_length, addr));
2350         }
2351         else
2352         {
2353             UINT row, y;
2354
2355             /* glCompressedTexSubImage2DARB() ignores pixel store state, so we
2356              * can't use the unpack row length like below. */
2357             for (row = 0, y = dst_point->y; row < row_count; ++row)
2358             {
2359                 GL_EXTCALL(glCompressedTexSubImage2DARB(surface->texture_target, surface->texture_level,
2360                         dst_point->x, y, update_w, format->block_height, internal, row_length, addr));
2361                 y += format->block_height;
2362                 addr += src_pitch;
2363             }
2364         }
2365         checkGLcall("glCompressedTexSubImage2DARB");
2366     }
2367     else
2368     {
2369         const BYTE *addr = data->addr;
2370
2371         addr += src_rect->top * src_pitch;
2372         addr += src_rect->left * format->byte_count;
2373
2374         TRACE("glTexSubImage2D, target %#x, level %d, x %d, y %d, w %d, h %d, format %#x, type %#x, addr %p.\n",
2375                 surface->texture_target, surface->texture_level, dst_point->x, dst_point->y,
2376                 update_w, update_h, format->glFormat, format->glType, addr);
2377
2378         gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, src_pitch / format->byte_count);
2379         gl_info->gl_ops.gl.p_glTexSubImage2D(surface->texture_target, surface->texture_level,
2380                 dst_point->x, dst_point->y, update_w, update_h, format->glFormat, format->glType, addr);
2381         gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2382         checkGLcall("glTexSubImage2D");
2383     }
2384
2385     if (data->buffer_object)
2386     {
2387         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
2388         checkGLcall("glBindBufferARB");
2389     }
2390
2391     LEAVE_GL();
2392
2393     if (wined3d_settings.strict_draw_ordering)
2394         gl_info->gl_ops.gl.p_glFlush();
2395
2396     if (gl_info->quirks & WINED3D_QUIRK_FBO_TEX_UPDATE)
2397     {
2398         struct wined3d_device *device = surface->resource.device;
2399         unsigned int i;
2400
2401         for (i = 0; i < device->context_count; ++i)
2402         {
2403             context_surface_update(device->contexts[i], surface);
2404         }
2405     }
2406 }
2407
2408 static HRESULT d3dfmt_get_conv(const struct wined3d_surface *surface, BOOL need_alpha_ck, BOOL use_texturing,
2409         struct wined3d_format *format, enum wined3d_conversion_type *conversion_type)
2410 {
2411     BOOL colorkey_active = need_alpha_ck && (surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2412     const struct wined3d_device *device = surface->resource.device;
2413     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2414     BOOL blit_supported = FALSE;
2415
2416     /* Copy the default values from the surface. Below we might perform fixups */
2417     /* TODO: get rid of color keying desc fixups by using e.g. a table. */
2418     *format = *surface->resource.format;
2419     *conversion_type = WINED3D_CT_NONE;
2420
2421     /* Ok, now look if we have to do any conversion */
2422     switch (surface->resource.format->id)
2423     {
2424         case WINED3DFMT_P8_UINT:
2425             /* Below the call to blit_supported is disabled for Wine 1.2
2426              * because the function isn't operating correctly yet. At the
2427              * moment 8-bit blits are handled in software and if certain GL
2428              * extensions are around, surface conversion is performed at
2429              * upload time. The blit_supported call recognizes it as a
2430              * destination fixup. This type of upload 'fixup' and 8-bit to
2431              * 8-bit blits need to be handled by the blit_shader.
2432              * TODO: get rid of this #if 0. */
2433 #if 0
2434             blit_supported = device->blitter->blit_supported(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
2435                     &rect, surface->resource.usage, surface->resource.pool, surface->resource.format,
2436                     &rect, surface->resource.usage, surface->resource.pool, surface->resource.format);
2437 #endif
2438             blit_supported = gl_info->supported[EXT_PALETTED_TEXTURE] || gl_info->supported[ARB_FRAGMENT_PROGRAM];
2439
2440             /* Use conversion when the blit_shader backend supports it. It only supports this in case of
2441              * texturing. Further also use conversion in case of color keying.
2442              * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2443              * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2444              * conflicts with this.
2445              */
2446             if (!((blit_supported && device->fb.render_targets && surface == device->fb.render_targets[0]))
2447                     || colorkey_active || !use_texturing)
2448             {
2449                 format->glFormat = GL_RGBA;
2450                 format->glInternal = GL_RGBA;
2451                 format->glType = GL_UNSIGNED_BYTE;
2452                 format->conv_byte_count = 4;
2453                 if (colorkey_active)
2454                     *conversion_type = WINED3D_CT_PALETTED_CK;
2455                 else
2456                     *conversion_type = WINED3D_CT_PALETTED;
2457             }
2458             break;
2459
2460         case WINED3DFMT_B2G3R3_UNORM:
2461             /* **********************
2462                 GL_UNSIGNED_BYTE_3_3_2
2463                 ********************** */
2464             if (colorkey_active) {
2465                 /* This texture format will never be used.. So do not care about color keying
2466                     up until the point in time it will be needed :-) */
2467                 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2468             }
2469             break;
2470
2471         case WINED3DFMT_B5G6R5_UNORM:
2472             if (colorkey_active)
2473             {
2474                 *conversion_type = WINED3D_CT_CK_565;
2475                 format->glFormat = GL_RGBA;
2476                 format->glInternal = GL_RGB5_A1;
2477                 format->glType = GL_UNSIGNED_SHORT_5_5_5_1;
2478                 format->conv_byte_count = 2;
2479             }
2480             break;
2481
2482         case WINED3DFMT_B5G5R5X1_UNORM:
2483             if (colorkey_active)
2484             {
2485                 *conversion_type = WINED3D_CT_CK_5551;
2486                 format->glFormat = GL_BGRA;
2487                 format->glInternal = GL_RGB5_A1;
2488                 format->glType = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2489                 format->conv_byte_count = 2;
2490             }
2491             break;
2492
2493         case WINED3DFMT_B8G8R8_UNORM:
2494             if (colorkey_active)
2495             {
2496                 *conversion_type = WINED3D_CT_CK_RGB24;
2497                 format->glFormat = GL_RGBA;
2498                 format->glInternal = GL_RGBA8;
2499                 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2500                 format->conv_byte_count = 4;
2501             }
2502             break;
2503
2504         case WINED3DFMT_B8G8R8X8_UNORM:
2505             if (colorkey_active)
2506             {
2507                 *conversion_type = WINED3D_CT_RGB32_888;
2508                 format->glFormat = GL_RGBA;
2509                 format->glInternal = GL_RGBA8;
2510                 format->glType = GL_UNSIGNED_INT_8_8_8_8;
2511                 format->conv_byte_count = 4;
2512             }
2513             break;
2514
2515         case WINED3DFMT_B8G8R8A8_UNORM:
2516             if (colorkey_active)
2517             {
2518                 *conversion_type = WINED3D_CT_CK_ARGB32;
2519                 format->conv_byte_count = 4;
2520             }
2521             break;
2522
2523         default:
2524             break;
2525     }
2526
2527     if (*conversion_type != WINED3D_CT_NONE)
2528     {
2529         format->rtInternal = format->glInternal;
2530         format->glGammaInternal = format->glInternal;
2531     }
2532
2533     return WINED3D_OK;
2534 }
2535
2536 static BOOL surface_check_block_align(struct wined3d_surface *surface, const RECT *rect)
2537 {
2538     UINT width_mask, height_mask;
2539
2540     if (!rect->left && !rect->top
2541             && rect->right == surface->resource.width
2542             && rect->bottom == surface->resource.height)
2543         return TRUE;
2544
2545     /* This assumes power of two block sizes, but NPOT block sizes would be
2546      * silly anyway. */
2547     width_mask = surface->resource.format->block_width - 1;
2548     height_mask = surface->resource.format->block_height - 1;
2549
2550     if (!(rect->left & width_mask) && !(rect->top & height_mask)
2551             && !(rect->right & width_mask) && !(rect->bottom & height_mask))
2552         return TRUE;
2553
2554     return FALSE;
2555 }
2556
2557 HRESULT surface_upload_from_surface(struct wined3d_surface *dst_surface, const POINT *dst_point,
2558         struct wined3d_surface *src_surface, const RECT *src_rect)
2559 {
2560     const struct wined3d_format *src_format;
2561     const struct wined3d_format *dst_format;
2562     const struct wined3d_gl_info *gl_info;
2563     enum wined3d_conversion_type convert;
2564     struct wined3d_context *context;
2565     struct wined3d_bo_address data;
2566     struct wined3d_format format;
2567     UINT update_w, update_h;
2568     UINT dst_w, dst_h;
2569     RECT r, dst_rect;
2570     UINT src_pitch;
2571     POINT p;
2572
2573     TRACE("dst_surface %p, dst_point %s, src_surface %p, src_rect %s.\n",
2574             dst_surface, wine_dbgstr_point(dst_point),
2575             src_surface, wine_dbgstr_rect(src_rect));
2576
2577     src_format = src_surface->resource.format;
2578     dst_format = dst_surface->resource.format;
2579
2580     if (src_format->id != dst_format->id)
2581     {
2582         WARN("Source and destination surfaces should have the same format.\n");
2583         return WINED3DERR_INVALIDCALL;
2584     }
2585
2586     if (!dst_point)
2587     {
2588         p.x = 0;
2589         p.y = 0;
2590         dst_point = &p;
2591     }
2592     else if (dst_point->x < 0 || dst_point->y < 0)
2593     {
2594         WARN("Invalid destination point.\n");
2595         return WINED3DERR_INVALIDCALL;
2596     }
2597
2598     if (!src_rect)
2599     {
2600         r.left = 0;
2601         r.top = 0;
2602         r.right = src_surface->resource.width;
2603         r.bottom = src_surface->resource.height;
2604         src_rect = &r;
2605     }
2606     else if (src_rect->left < 0 || src_rect->left >= src_rect->right
2607             || src_rect->top < 0 || src_rect->top >= src_rect->bottom)
2608     {
2609         WARN("Invalid source rectangle.\n");
2610         return WINED3DERR_INVALIDCALL;
2611     }
2612
2613     dst_w = dst_surface->resource.width;
2614     dst_h = dst_surface->resource.height;
2615
2616     update_w = src_rect->right - src_rect->left;
2617     update_h = src_rect->bottom - src_rect->top;
2618
2619     if (update_w > dst_w || dst_point->x > dst_w - update_w
2620             || update_h > dst_h || dst_point->y > dst_h - update_h)
2621     {
2622         WARN("Destination out of bounds.\n");
2623         return WINED3DERR_INVALIDCALL;
2624     }
2625
2626     if ((src_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(src_surface, src_rect))
2627     {
2628         WARN("Source rectangle not block-aligned.\n");
2629         return WINED3DERR_INVALIDCALL;
2630     }
2631
2632     SetRect(&dst_rect, dst_point->x, dst_point->y, dst_point->x + update_w, dst_point->y + update_h);
2633     if ((dst_format->flags & WINED3DFMT_FLAG_BLOCKS) && !surface_check_block_align(dst_surface, &dst_rect))
2634     {
2635         WARN("Destination rectangle not block-aligned.\n");
2636         return WINED3DERR_INVALIDCALL;
2637     }
2638
2639     /* Use wined3d_surface_blt() instead of uploading directly if we need conversion. */
2640     d3dfmt_get_conv(dst_surface, FALSE, TRUE, &format, &convert);
2641     if (convert != WINED3D_CT_NONE || format.convert)
2642         return wined3d_surface_blt(dst_surface, &dst_rect, src_surface, src_rect, 0, NULL, WINED3D_TEXF_POINT);
2643
2644     context = context_acquire(dst_surface->resource.device, NULL);
2645     gl_info = context->gl_info;
2646
2647     /* Only load the surface for partial updates. For newly allocated texture
2648      * the texture wouldn't be the current location, and we'd upload zeroes
2649      * just to overwrite them again. */
2650     if (update_w == dst_w && update_h == dst_h)
2651         surface_prepare_texture(dst_surface, context, FALSE);
2652     else
2653         surface_load_location(dst_surface, SFLAG_INTEXTURE, NULL);
2654     surface_bind(dst_surface, context, FALSE);
2655
2656     data.buffer_object = src_surface->pbo;
2657     data.addr = src_surface->resource.allocatedMemory;
2658     src_pitch = wined3d_surface_get_pitch(src_surface);
2659
2660     surface_upload_data(dst_surface, gl_info, src_format, src_rect, src_pitch, dst_point, FALSE, &data);
2661
2662     invalidate_active_texture(dst_surface->resource.device, context);
2663
2664     context_release(context);
2665
2666     surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
2667     return WINED3D_OK;
2668 }
2669
2670 /* This call just allocates the texture, the caller is responsible for binding
2671  * the correct texture. */
2672 /* Context activation is done by the caller. */
2673 static void surface_allocate_surface(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info,
2674         const struct wined3d_format *format, BOOL srgb)
2675 {
2676     BOOL enable_client_storage = FALSE;
2677     GLsizei width = surface->pow2Width;
2678     GLsizei height = surface->pow2Height;
2679     const BYTE *mem = NULL;
2680     GLenum internal;
2681
2682     if (srgb)
2683     {
2684         internal = format->glGammaInternal;
2685     }
2686     else if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET && surface_is_offscreen(surface))
2687     {
2688         internal = format->rtInternal;
2689     }
2690     else
2691     {
2692         internal = format->glInternal;
2693     }
2694
2695     if (!internal)
2696         FIXME("No GL internal format for format %s.\n", debug_d3dformat(format->id));
2697
2698     if (format->flags & WINED3DFMT_FLAG_HEIGHT_SCALE)
2699     {
2700         height *= format->height_scale.numerator;
2701         height /= format->height_scale.denominator;
2702     }
2703
2704     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",
2705             surface, surface->texture_target, surface->texture_level, debug_d3dformat(format->id),
2706             internal, width, height, format->glFormat, format->glType);
2707
2708     ENTER_GL();
2709
2710     if (gl_info->supported[APPLE_CLIENT_STORAGE])
2711     {
2712         if (surface->flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED)
2713                 || !surface->resource.allocatedMemory)
2714         {
2715             /* In some cases we want to disable client storage.
2716              * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
2717              * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
2718              * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
2719              * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
2720              */
2721             gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2722             checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2723             surface->flags &= ~SFLAG_CLIENT;
2724             enable_client_storage = TRUE;
2725         }
2726         else
2727         {
2728             surface->flags |= SFLAG_CLIENT;
2729
2730             /* Point OpenGL to our allocated texture memory. Do not use
2731              * resource.allocatedMemory here because it might point into a
2732              * PBO. Instead use heapMemory, but get the alignment right. */
2733             mem = (BYTE *)(((ULONG_PTR)surface->resource.heapMemory
2734                     + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
2735         }
2736     }
2737
2738     if (format->flags & WINED3DFMT_FLAG_COMPRESSED && mem)
2739     {
2740         GL_EXTCALL(glCompressedTexImage2DARB(surface->texture_target, surface->texture_level,
2741                 internal, width, height, 0, surface->resource.size, mem));
2742         checkGLcall("glCompressedTexImage2DARB");
2743     }
2744     else
2745     {
2746         gl_info->gl_ops.gl.p_glTexImage2D(surface->texture_target, surface->texture_level,
2747                 internal, width, height, 0, format->glFormat, format->glType, mem);
2748         checkGLcall("glTexImage2D");
2749     }
2750
2751     if (enable_client_storage)
2752     {
2753         gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2754         checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2755     }
2756     LEAVE_GL();
2757 }
2758
2759 /* In D3D the depth stencil dimensions have to be greater than or equal to the
2760  * render target dimensions. With FBOs, the dimensions have to be an exact match. */
2761 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
2762 /* GL locking is done by the caller */
2763 void surface_set_compatible_renderbuffer(struct wined3d_surface *surface, const struct wined3d_surface *rt)
2764 {
2765     const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
2766     struct wined3d_renderbuffer_entry *entry;
2767     GLuint renderbuffer = 0;
2768     unsigned int src_width, src_height;
2769     unsigned int width, height;
2770
2771     if (rt && rt->resource.format->id != WINED3DFMT_NULL)
2772     {
2773         width = rt->pow2Width;
2774         height = rt->pow2Height;
2775     }
2776     else
2777     {
2778         width = surface->pow2Width;
2779         height = surface->pow2Height;
2780     }
2781
2782     src_width = surface->pow2Width;
2783     src_height = surface->pow2Height;
2784
2785     /* A depth stencil smaller than the render target is not valid */
2786     if (width > src_width || height > src_height) return;
2787
2788     /* Remove any renderbuffer set if the sizes match */
2789     if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
2790             || (width == src_width && height == src_height))
2791     {
2792         surface->current_renderbuffer = NULL;
2793         return;
2794     }
2795
2796     /* Look if we've already got a renderbuffer of the correct dimensions */
2797     LIST_FOR_EACH_ENTRY(entry, &surface->renderbuffers, struct wined3d_renderbuffer_entry, entry)
2798     {
2799         if (entry->width == width && entry->height == height)
2800         {
2801             renderbuffer = entry->id;
2802             surface->current_renderbuffer = entry;
2803             break;
2804         }
2805     }
2806
2807     if (!renderbuffer)
2808     {
2809         gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
2810         gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
2811         gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
2812                 surface->resource.format->glInternal, width, height);
2813
2814         entry = HeapAlloc(GetProcessHeap(), 0, sizeof(*entry));
2815         entry->width = width;
2816         entry->height = height;
2817         entry->id = renderbuffer;
2818         list_add_head(&surface->renderbuffers, &entry->entry);
2819
2820         surface->current_renderbuffer = entry;
2821     }
2822
2823     checkGLcall("set_compatible_renderbuffer");
2824 }
2825
2826 GLenum surface_get_gl_buffer(const struct wined3d_surface *surface)
2827 {
2828     const struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
2829
2830     TRACE("surface %p.\n", surface);
2831
2832     if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN)
2833     {
2834         ERR("Surface %p is not on a swapchain.\n", surface);
2835         return GL_NONE;
2836     }
2837
2838     if (swapchain->back_buffers && swapchain->back_buffers[0] == surface)
2839     {
2840         if (swapchain->render_to_fbo)
2841         {
2842             TRACE("Returning GL_COLOR_ATTACHMENT0\n");
2843             return GL_COLOR_ATTACHMENT0;
2844         }
2845         TRACE("Returning GL_BACK\n");
2846         return GL_BACK;
2847     }
2848     else if (surface == swapchain->front_buffer)
2849     {
2850         TRACE("Returning GL_FRONT\n");
2851         return GL_FRONT;
2852     }
2853
2854     FIXME("Higher back buffer, returning GL_BACK\n");
2855     return GL_BACK;
2856 }
2857
2858 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
2859 void surface_add_dirty_rect(struct wined3d_surface *surface, const struct wined3d_box *dirty_rect)
2860 {
2861     TRACE("surface %p, dirty_rect %p.\n", surface, dirty_rect);
2862
2863     if (!(surface->flags & SFLAG_INSYSMEM) && (surface->flags & SFLAG_INTEXTURE))
2864         /* No partial locking for textures yet. */
2865         surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2866
2867     surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2868     if (dirty_rect)
2869     {
2870         surface->dirtyRect.left = min(surface->dirtyRect.left, dirty_rect->left);
2871         surface->dirtyRect.top = min(surface->dirtyRect.top, dirty_rect->top);
2872         surface->dirtyRect.right = max(surface->dirtyRect.right, dirty_rect->right);
2873         surface->dirtyRect.bottom = max(surface->dirtyRect.bottom, dirty_rect->bottom);
2874     }
2875     else
2876     {
2877         surface->dirtyRect.left = 0;
2878         surface->dirtyRect.top = 0;
2879         surface->dirtyRect.right = surface->resource.width;
2880         surface->dirtyRect.bottom = surface->resource.height;
2881     }
2882
2883     /* if the container is a texture then mark it dirty. */
2884     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
2885     {
2886         TRACE("Passing to container.\n");
2887         wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
2888     }
2889 }
2890
2891 HRESULT surface_load(struct wined3d_surface *surface, BOOL srgb)
2892 {
2893     DWORD flag = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2894     BOOL ck_changed;
2895
2896     TRACE("surface %p, srgb %#x.\n", surface, srgb);
2897
2898     if (surface->resource.pool == WINED3D_POOL_SCRATCH)
2899     {
2900         ERR("Not supported on scratch surfaces.\n");
2901         return WINED3DERR_INVALIDCALL;
2902     }
2903
2904     ck_changed = !(surface->flags & SFLAG_GLCKEY) != !(surface->CKeyFlags & WINEDDSD_CKSRCBLT);
2905
2906     /* Reload if either the texture and sysmem have different ideas about the
2907      * color key, or the actual key values changed. */
2908     if (ck_changed || ((surface->CKeyFlags & WINEDDSD_CKSRCBLT)
2909             && (surface->gl_color_key.color_space_low_value != surface->src_blt_color_key.color_space_low_value
2910             || surface->gl_color_key.color_space_high_value != surface->src_blt_color_key.color_space_high_value)))
2911     {
2912         TRACE("Reloading because of color keying\n");
2913         /* To perform the color key conversion we need a sysmem copy of
2914          * the surface. Make sure we have it. */
2915
2916         surface_load_location(surface, SFLAG_INSYSMEM, NULL);
2917         /* Make sure the texture is reloaded because of the color key change,
2918          * this kills performance though :( */
2919         /* TODO: This is not necessarily needed with hw palettized texture support. */
2920         surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
2921         /* Switching color keying on / off may change the internal format. */
2922         if (ck_changed)
2923             surface_force_reload(surface);
2924     }
2925     else if (!(surface->flags & flag))
2926     {
2927         TRACE("Reloading because surface is dirty.\n");
2928     }
2929     else
2930     {
2931         TRACE("surface is already in texture\n");
2932         return WINED3D_OK;
2933     }
2934
2935     /* No partial locking for textures yet. */
2936     surface_load_location(surface, flag, NULL);
2937     surface_evict_sysmem(surface);
2938
2939     return WINED3D_OK;
2940 }
2941
2942 /* See also float_16_to_32() in wined3d_private.h */
2943 static inline unsigned short float_32_to_16(const float *in)
2944 {
2945     int exp = 0;
2946     float tmp = fabsf(*in);
2947     unsigned int mantissa;
2948     unsigned short ret;
2949
2950     /* Deal with special numbers */
2951     if (*in == 0.0f)
2952         return 0x0000;
2953     if (isnan(*in))
2954         return 0x7c01;
2955     if (isinf(*in))
2956         return (*in < 0.0f ? 0xfc00 : 0x7c00);
2957
2958     if (tmp < powf(2, 10))
2959     {
2960         do
2961         {
2962             tmp = tmp * 2.0f;
2963             exp--;
2964         } while (tmp < powf(2, 10));
2965     }
2966     else if (tmp >= powf(2, 11))
2967     {
2968         do
2969         {
2970             tmp /= 2.0f;
2971             exp++;
2972         } while (tmp >= powf(2, 11));
2973     }
2974
2975     mantissa = (unsigned int)tmp;
2976     if (tmp - mantissa >= 0.5f)
2977         ++mantissa; /* Round to nearest, away from zero. */
2978
2979     exp += 10;  /* Normalize the mantissa. */
2980     exp += 15;  /* Exponent is encoded with excess 15. */
2981
2982     if (exp > 30) /* too big */
2983     {
2984         ret = 0x7c00; /* INF */
2985     }
2986     else if (exp <= 0)
2987     {
2988         /* exp == 0: Non-normalized mantissa. Returns 0x0000 (=0.0) for too small numbers. */
2989         while (exp <= 0)
2990         {
2991             mantissa = mantissa >> 1;
2992             ++exp;
2993         }
2994         ret = mantissa & 0x3ff;
2995     }
2996     else
2997     {
2998         ret = (exp << 10) | (mantissa & 0x3ff);
2999     }
3000
3001     ret |= ((*in < 0.0f ? 1 : 0) << 15); /* Add the sign */
3002     return ret;
3003 }
3004
3005 ULONG CDECL wined3d_surface_incref(struct wined3d_surface *surface)
3006 {
3007     ULONG refcount;
3008
3009     TRACE("Surface %p, container %p of type %#x.\n",
3010             surface, surface->container.u.base, surface->container.type);
3011
3012     switch (surface->container.type)
3013     {
3014         case WINED3D_CONTAINER_TEXTURE:
3015             return wined3d_texture_incref(surface->container.u.texture);
3016
3017         case WINED3D_CONTAINER_SWAPCHAIN:
3018             return wined3d_swapchain_incref(surface->container.u.swapchain);
3019
3020         default:
3021             ERR("Unhandled container type %#x.\n", surface->container.type);
3022         case WINED3D_CONTAINER_NONE:
3023             break;
3024     }
3025
3026     refcount = InterlockedIncrement(&surface->resource.ref);
3027     TRACE("%p increasing refcount to %u.\n", surface, refcount);
3028
3029     return refcount;
3030 }
3031
3032 /* Do not call while under the GL lock. */
3033 ULONG CDECL wined3d_surface_decref(struct wined3d_surface *surface)
3034 {
3035     ULONG refcount;
3036
3037     TRACE("Surface %p, container %p of type %#x.\n",
3038             surface, surface->container.u.base, surface->container.type);
3039
3040     switch (surface->container.type)
3041     {
3042         case WINED3D_CONTAINER_TEXTURE:
3043             return wined3d_texture_decref(surface->container.u.texture);
3044
3045         case WINED3D_CONTAINER_SWAPCHAIN:
3046             return wined3d_swapchain_decref(surface->container.u.swapchain);
3047
3048         default:
3049             ERR("Unhandled container type %#x.\n", surface->container.type);
3050         case WINED3D_CONTAINER_NONE:
3051             break;
3052     }
3053
3054     refcount = InterlockedDecrement(&surface->resource.ref);
3055     TRACE("%p decreasing refcount to %u.\n", surface, refcount);
3056
3057     if (!refcount)
3058     {
3059         surface_cleanup(surface);
3060         surface->resource.parent_ops->wined3d_object_destroyed(surface->resource.parent);
3061
3062         TRACE("Destroyed surface %p.\n", surface);
3063         HeapFree(GetProcessHeap(), 0, surface);
3064     }
3065
3066     return refcount;
3067 }
3068
3069 DWORD CDECL wined3d_surface_set_priority(struct wined3d_surface *surface, DWORD priority)
3070 {
3071     return resource_set_priority(&surface->resource, priority);
3072 }
3073
3074 DWORD CDECL wined3d_surface_get_priority(const struct wined3d_surface *surface)
3075 {
3076     return resource_get_priority(&surface->resource);
3077 }
3078
3079 void CDECL wined3d_surface_preload(struct wined3d_surface *surface)
3080 {
3081     TRACE("surface %p.\n", surface);
3082
3083     if (!surface->resource.device->d3d_initialized)
3084     {
3085         ERR("D3D not initialized.\n");
3086         return;
3087     }
3088
3089     surface_internal_preload(surface, SRGB_ANY);
3090 }
3091
3092 void * CDECL wined3d_surface_get_parent(const struct wined3d_surface *surface)
3093 {
3094     TRACE("surface %p.\n", surface);
3095
3096     return surface->resource.parent;
3097 }
3098
3099 struct wined3d_resource * CDECL wined3d_surface_get_resource(struct wined3d_surface *surface)
3100 {
3101     TRACE("surface %p.\n", surface);
3102
3103     return &surface->resource;
3104 }
3105
3106 HRESULT CDECL wined3d_surface_get_blt_status(const struct wined3d_surface *surface, DWORD flags)
3107 {
3108     TRACE("surface %p, flags %#x.\n", surface, flags);
3109
3110     switch (flags)
3111     {
3112         case WINEDDGBS_CANBLT:
3113         case WINEDDGBS_ISBLTDONE:
3114             return WINED3D_OK;
3115
3116         default:
3117             return WINED3DERR_INVALIDCALL;
3118     }
3119 }
3120
3121 HRESULT CDECL wined3d_surface_get_flip_status(const struct wined3d_surface *surface, DWORD flags)
3122 {
3123     TRACE("surface %p, flags %#x.\n", surface, flags);
3124
3125     /* XXX: DDERR_INVALIDSURFACETYPE */
3126
3127     switch (flags)
3128     {
3129         case WINEDDGFS_CANFLIP:
3130         case WINEDDGFS_ISFLIPDONE:
3131             return WINED3D_OK;
3132
3133         default:
3134             return WINED3DERR_INVALIDCALL;
3135     }
3136 }
3137
3138 HRESULT CDECL wined3d_surface_is_lost(const struct wined3d_surface *surface)
3139 {
3140     TRACE("surface %p.\n", surface);
3141
3142     /* D3D8 and 9 loose full devices, ddraw only surfaces. */
3143     return surface->flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
3144 }
3145
3146 HRESULT CDECL wined3d_surface_restore(struct wined3d_surface *surface)
3147 {
3148     TRACE("surface %p.\n", surface);
3149
3150     surface->flags &= ~SFLAG_LOST;
3151     return WINED3D_OK;
3152 }
3153
3154 void CDECL wined3d_surface_set_palette(struct wined3d_surface *surface, struct wined3d_palette *palette)
3155 {
3156     TRACE("surface %p, palette %p.\n", surface, palette);
3157
3158     if (surface->palette == palette)
3159     {
3160         TRACE("Nop palette change.\n");
3161         return;
3162     }
3163
3164     if (surface->palette && (surface->resource.usage & WINED3DUSAGE_RENDERTARGET))
3165         surface->palette->flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
3166
3167     surface->palette = palette;
3168
3169     if (palette)
3170     {
3171         if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3172             palette->flags |= WINEDDPCAPS_PRIMARYSURFACE;
3173
3174         surface->surface_ops->surface_realize_palette(surface);
3175     }
3176 }
3177
3178 HRESULT CDECL wined3d_surface_set_color_key(struct wined3d_surface *surface,
3179         DWORD flags, const struct wined3d_color_key *color_key)
3180 {
3181     TRACE("surface %p, flags %#x, color_key %p.\n", surface, flags, color_key);
3182
3183     if (flags & WINEDDCKEY_COLORSPACE)
3184     {
3185         FIXME(" colorkey value not supported (%08x) !\n", flags);
3186         return WINED3DERR_INVALIDCALL;
3187     }
3188
3189     /* Dirtify the surface, but only if a key was changed. */
3190     if (color_key)
3191     {
3192         switch (flags & ~WINEDDCKEY_COLORSPACE)
3193         {
3194             case WINEDDCKEY_DESTBLT:
3195                 surface->dst_blt_color_key = *color_key;
3196                 surface->CKeyFlags |= WINEDDSD_CKDESTBLT;
3197                 break;
3198
3199             case WINEDDCKEY_DESTOVERLAY:
3200                 surface->dst_overlay_color_key = *color_key;
3201                 surface->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
3202                 break;
3203
3204             case WINEDDCKEY_SRCOVERLAY:
3205                 surface->src_overlay_color_key = *color_key;
3206                 surface->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
3207                 break;
3208
3209             case WINEDDCKEY_SRCBLT:
3210                 surface->src_blt_color_key = *color_key;
3211                 surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
3212                 break;
3213         }
3214     }
3215     else
3216     {
3217         switch (flags & ~WINEDDCKEY_COLORSPACE)
3218         {
3219             case WINEDDCKEY_DESTBLT:
3220                 surface->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
3221                 break;
3222
3223             case WINEDDCKEY_DESTOVERLAY:
3224                 surface->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
3225                 break;
3226
3227             case WINEDDCKEY_SRCOVERLAY:
3228                 surface->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
3229                 break;
3230
3231             case WINEDDCKEY_SRCBLT:
3232                 surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3233                 break;
3234         }
3235     }
3236
3237     return WINED3D_OK;
3238 }
3239
3240 struct wined3d_palette * CDECL wined3d_surface_get_palette(const struct wined3d_surface *surface)
3241 {
3242     TRACE("surface %p.\n", surface);
3243
3244     return surface->palette;
3245 }
3246
3247 DWORD CDECL wined3d_surface_get_pitch(const struct wined3d_surface *surface)
3248 {
3249     const struct wined3d_format *format = surface->resource.format;
3250     DWORD pitch;
3251
3252     TRACE("surface %p.\n", surface);
3253
3254     if (format->flags & WINED3DFMT_FLAG_BLOCKS)
3255     {
3256         /* Since compressed formats are block based, pitch means the amount of
3257          * bytes to the next row of block rather than the next row of pixels. */
3258         UINT row_block_count = (surface->resource.width + format->block_width - 1) / format->block_width;
3259         pitch = row_block_count * format->block_byte_count;
3260     }
3261     else
3262     {
3263         unsigned char alignment = surface->resource.device->surface_alignment;
3264         pitch = surface->resource.format->byte_count * surface->resource.width;  /* Bytes / row */
3265         pitch = (pitch + alignment - 1) & ~(alignment - 1);
3266     }
3267
3268     TRACE("Returning %u.\n", pitch);
3269
3270     return pitch;
3271 }
3272
3273 HRESULT CDECL wined3d_surface_set_mem(struct wined3d_surface *surface, void *mem)
3274 {
3275     TRACE("surface %p, mem %p.\n", surface, mem);
3276
3277     if (surface->resource.map_count || (surface->flags & SFLAG_DCINUSE))
3278     {
3279         WARN("Surface is mapped or the DC is in use.\n");
3280         return WINED3DERR_INVALIDCALL;
3281     }
3282
3283     /* Render targets depend on their hdc, and we can't create an hdc on a user pointer. */
3284     if (surface->resource.usage & WINED3DUSAGE_RENDERTARGET)
3285     {
3286         ERR("Not supported on render targets.\n");
3287         return WINED3DERR_INVALIDCALL;
3288     }
3289
3290     if (mem && mem != surface->resource.allocatedMemory)
3291     {
3292         void *release = NULL;
3293
3294         /* Do I have to copy the old surface content? */
3295         if (surface->flags & SFLAG_DIBSECTION)
3296         {
3297             DeleteDC(surface->hDC);
3298             DeleteObject(surface->dib.DIBsection);
3299             surface->dib.bitmap_data = NULL;
3300             surface->resource.allocatedMemory = NULL;
3301             surface->hDC = NULL;
3302             surface->flags &= ~SFLAG_DIBSECTION;
3303         }
3304         else if (!(surface->flags & SFLAG_USERPTR))
3305         {
3306             release = surface->resource.heapMemory;
3307             surface->resource.heapMemory = NULL;
3308         }
3309         surface->resource.allocatedMemory = mem;
3310         surface->flags |= SFLAG_USERPTR;
3311
3312         /* Now the surface memory is most up do date. Invalidate drawable and texture. */
3313         surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3314
3315         /* For client textures OpenGL has to be notified. */
3316         if (surface->flags & SFLAG_CLIENT)
3317             surface_release_client_storage(surface);
3318
3319         /* Now free the old memory if any. */
3320         HeapFree(GetProcessHeap(), 0, release);
3321     }
3322     else if (surface->flags & SFLAG_USERPTR)
3323     {
3324         /* HeapMemory should be NULL already. */
3325         if (surface->resource.heapMemory)
3326             ERR("User pointer surface has heap memory allocated.\n");
3327
3328         if (!mem)
3329         {
3330             surface->resource.allocatedMemory = NULL;
3331             surface->flags &= ~(SFLAG_USERPTR | SFLAG_INSYSMEM);
3332
3333             if (surface->flags & SFLAG_CLIENT)
3334                 surface_release_client_storage(surface);
3335
3336             surface_prepare_system_memory(surface);
3337         }
3338
3339         surface_modify_location(surface, SFLAG_INSYSMEM, TRUE);
3340     }
3341
3342     return WINED3D_OK;
3343 }
3344
3345 HRESULT CDECL wined3d_surface_set_overlay_position(struct wined3d_surface *surface, LONG x, LONG y)
3346 {
3347     LONG w, h;
3348
3349     TRACE("surface %p, x %d, y %d.\n", surface, x, y);
3350
3351     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3352     {
3353         WARN("Not an overlay surface.\n");
3354         return WINEDDERR_NOTAOVERLAYSURFACE;
3355     }
3356
3357     w = surface->overlay_destrect.right - surface->overlay_destrect.left;
3358     h = surface->overlay_destrect.bottom - surface->overlay_destrect.top;
3359     surface->overlay_destrect.left = x;
3360     surface->overlay_destrect.top = y;
3361     surface->overlay_destrect.right = x + w;
3362     surface->overlay_destrect.bottom = y + h;
3363
3364     surface_draw_overlay(surface);
3365
3366     return WINED3D_OK;
3367 }
3368
3369 HRESULT CDECL wined3d_surface_get_overlay_position(const struct wined3d_surface *surface, LONG *x, LONG *y)
3370 {
3371     TRACE("surface %p, x %p, y %p.\n", surface, x, y);
3372
3373     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3374     {
3375         TRACE("Not an overlay surface.\n");
3376         return WINEDDERR_NOTAOVERLAYSURFACE;
3377     }
3378
3379     if (!surface->overlay_dest)
3380     {
3381         TRACE("Overlay not visible.\n");
3382         *x = 0;
3383         *y = 0;
3384         return WINEDDERR_OVERLAYNOTVISIBLE;
3385     }
3386
3387     *x = surface->overlay_destrect.left;
3388     *y = surface->overlay_destrect.top;
3389
3390     TRACE("Returning position %d, %d.\n", *x, *y);
3391
3392     return WINED3D_OK;
3393 }
3394
3395 HRESULT CDECL wined3d_surface_update_overlay_z_order(struct wined3d_surface *surface,
3396         DWORD flags, struct wined3d_surface *ref)
3397 {
3398     FIXME("surface %p, flags %#x, ref %p stub!\n", surface, flags, ref);
3399
3400     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3401     {
3402         TRACE("Not an overlay surface.\n");
3403         return WINEDDERR_NOTAOVERLAYSURFACE;
3404     }
3405
3406     return WINED3D_OK;
3407 }
3408
3409 HRESULT CDECL wined3d_surface_update_overlay(struct wined3d_surface *surface, const RECT *src_rect,
3410         struct wined3d_surface *dst_surface, const RECT *dst_rect, DWORD flags, const WINEDDOVERLAYFX *fx)
3411 {
3412     TRACE("surface %p, src_rect %s, dst_surface %p, dst_rect %s, flags %#x, fx %p.\n",
3413             surface, wine_dbgstr_rect(src_rect), dst_surface, wine_dbgstr_rect(dst_rect), flags, fx);
3414
3415     if (!(surface->resource.usage & WINED3DUSAGE_OVERLAY))
3416     {
3417         WARN("Not an overlay surface.\n");
3418         return WINEDDERR_NOTAOVERLAYSURFACE;
3419     }
3420     else if (!dst_surface)
3421     {
3422         WARN("Dest surface is NULL.\n");
3423         return WINED3DERR_INVALIDCALL;
3424     }
3425
3426     if (src_rect)
3427     {
3428         surface->overlay_srcrect = *src_rect;
3429     }
3430     else
3431     {
3432         surface->overlay_srcrect.left = 0;
3433         surface->overlay_srcrect.top = 0;
3434         surface->overlay_srcrect.right = surface->resource.width;
3435         surface->overlay_srcrect.bottom = surface->resource.height;
3436     }
3437
3438     if (dst_rect)
3439     {
3440         surface->overlay_destrect = *dst_rect;
3441     }
3442     else
3443     {
3444         surface->overlay_destrect.left = 0;
3445         surface->overlay_destrect.top = 0;
3446         surface->overlay_destrect.right = dst_surface ? dst_surface->resource.width : 0;
3447         surface->overlay_destrect.bottom = dst_surface ? dst_surface->resource.height : 0;
3448     }
3449
3450     if (surface->overlay_dest && (surface->overlay_dest != dst_surface || flags & WINEDDOVER_HIDE))
3451     {
3452         surface->overlay_dest = NULL;
3453         list_remove(&surface->overlay_entry);
3454     }
3455
3456     if (flags & WINEDDOVER_SHOW)
3457     {
3458         if (surface->overlay_dest != dst_surface)
3459         {
3460             surface->overlay_dest = dst_surface;
3461             list_add_tail(&dst_surface->overlays, &surface->overlay_entry);
3462         }
3463     }
3464     else if (flags & WINEDDOVER_HIDE)
3465     {
3466         /* tests show that the rectangles are erased on hide */
3467         surface->overlay_srcrect.left = 0; surface->overlay_srcrect.top = 0;
3468         surface->overlay_srcrect.right = 0; surface->overlay_srcrect.bottom = 0;
3469         surface->overlay_destrect.left = 0; surface->overlay_destrect.top = 0;
3470         surface->overlay_destrect.right = 0; surface->overlay_destrect.bottom = 0;
3471         surface->overlay_dest = NULL;
3472     }
3473
3474     surface_draw_overlay(surface);
3475
3476     return WINED3D_OK;
3477 }
3478
3479 HRESULT CDECL wined3d_surface_update_desc(struct wined3d_surface *surface,
3480         UINT width, UINT height, enum wined3d_format_id format_id,
3481         enum wined3d_multisample_type multisample_type, UINT multisample_quality)
3482 {
3483     struct wined3d_device *device = surface->resource.device;
3484     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
3485     const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
3486     UINT resource_size = wined3d_format_calculate_size(format, device->surface_alignment, width, height);
3487
3488     TRACE("surface %p, width %u, height %u, format %s, multisample_type %#x, multisample_quality %u.\n",
3489             surface, width, height, debug_d3dformat(format_id), multisample_type, multisample_type);
3490
3491     if (!resource_size)
3492         return WINED3DERR_INVALIDCALL;
3493
3494     if (device->d3d_initialized)
3495         surface->resource.resource_ops->resource_unload(&surface->resource);
3496
3497     if (surface->flags & SFLAG_DIBSECTION)
3498     {
3499         DeleteDC(surface->hDC);
3500         DeleteObject(surface->dib.DIBsection);
3501         surface->dib.bitmap_data = NULL;
3502         surface->flags &= ~SFLAG_DIBSECTION;
3503     }
3504
3505     surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_USERPTR);
3506     surface->resource.allocatedMemory = NULL;
3507     HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
3508     surface->resource.heapMemory = NULL;
3509
3510     surface->resource.width = width;
3511     surface->resource.height = height;
3512     if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[ARB_TEXTURE_RECTANGLE]
3513             || gl_info->supported[WINED3D_GL_NORMALIZED_TEXRECT])
3514     {
3515         surface->pow2Width = width;
3516         surface->pow2Height = height;
3517     }
3518     else
3519     {
3520         surface->pow2Width = surface->pow2Height = 1;
3521         while (surface->pow2Width < width)
3522             surface->pow2Width <<= 1;
3523         while (surface->pow2Height < height)
3524             surface->pow2Height <<= 1;
3525     }
3526
3527     if (surface->pow2Width != width || surface->pow2Height != height)
3528         surface->flags |= SFLAG_NONPOW2;
3529     else
3530         surface->flags &= ~SFLAG_NONPOW2;
3531
3532     surface->resource.format = format;
3533     surface->resource.multisample_type = multisample_type;
3534     surface->resource.multisample_quality = multisample_quality;
3535     surface->resource.size = resource_size;
3536
3537     if (!surface_init_sysmem(surface))
3538         return E_OUTOFMEMORY;
3539
3540     return WINED3D_OK;
3541 }
3542
3543 static void convert_r32_float_r16_float(const BYTE *src, BYTE *dst,
3544         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3545 {
3546     unsigned short *dst_s;
3547     const float *src_f;
3548     unsigned int x, y;
3549
3550     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3551
3552     for (y = 0; y < h; ++y)
3553     {
3554         src_f = (const float *)(src + y * pitch_in);
3555         dst_s = (unsigned short *) (dst + y * pitch_out);
3556         for (x = 0; x < w; ++x)
3557         {
3558             dst_s[x] = float_32_to_16(src_f + x);
3559         }
3560     }
3561 }
3562
3563 static void convert_r5g6b5_x8r8g8b8(const BYTE *src, BYTE *dst,
3564         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3565 {
3566     static const unsigned char convert_5to8[] =
3567     {
3568         0x00, 0x08, 0x10, 0x19, 0x21, 0x29, 0x31, 0x3a,
3569         0x42, 0x4a, 0x52, 0x5a, 0x63, 0x6b, 0x73, 0x7b,
3570         0x84, 0x8c, 0x94, 0x9c, 0xa5, 0xad, 0xb5, 0xbd,
3571         0xc5, 0xce, 0xd6, 0xde, 0xe6, 0xef, 0xf7, 0xff,
3572     };
3573     static const unsigned char convert_6to8[] =
3574     {
3575         0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
3576         0x20, 0x24, 0x28, 0x2d, 0x31, 0x35, 0x39, 0x3d,
3577         0x41, 0x45, 0x49, 0x4d, 0x51, 0x55, 0x59, 0x5d,
3578         0x61, 0x65, 0x69, 0x6d, 0x71, 0x75, 0x79, 0x7d,
3579         0x82, 0x86, 0x8a, 0x8e, 0x92, 0x96, 0x9a, 0x9e,
3580         0xa2, 0xa6, 0xaa, 0xae, 0xb2, 0xb6, 0xba, 0xbe,
3581         0xc2, 0xc6, 0xca, 0xce, 0xd2, 0xd7, 0xdb, 0xdf,
3582         0xe3, 0xe7, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xff,
3583     };
3584     unsigned int x, y;
3585
3586     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3587
3588     for (y = 0; y < h; ++y)
3589     {
3590         const WORD *src_line = (const WORD *)(src + y * pitch_in);
3591         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3592         for (x = 0; x < w; ++x)
3593         {
3594             WORD pixel = src_line[x];
3595             dst_line[x] = 0xff000000
3596                     | convert_5to8[(pixel & 0xf800) >> 11] << 16
3597                     | convert_6to8[(pixel & 0x07e0) >> 5] << 8
3598                     | convert_5to8[(pixel & 0x001f)];
3599         }
3600     }
3601 }
3602
3603 /* We use this for both B8G8R8A8 -> B8G8R8X8 and B8G8R8X8 -> B8G8R8A8, since
3604  * in both cases we're just setting the X / Alpha channel to 0xff. */
3605 static void convert_a8r8g8b8_x8r8g8b8(const BYTE *src, BYTE *dst,
3606         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3607 {
3608     unsigned int x, y;
3609
3610     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3611
3612     for (y = 0; y < h; ++y)
3613     {
3614         const DWORD *src_line = (const DWORD *)(src + y * pitch_in);
3615         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3616
3617         for (x = 0; x < w; ++x)
3618         {
3619             dst_line[x] = 0xff000000 | (src_line[x] & 0xffffff);
3620         }
3621     }
3622 }
3623
3624 static inline BYTE cliptobyte(int x)
3625 {
3626     return (BYTE)((x < 0) ? 0 : ((x > 255) ? 255 : x));
3627 }
3628
3629 static void convert_yuy2_x8r8g8b8(const BYTE *src, BYTE *dst,
3630         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3631 {
3632     int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3633     unsigned int x, y;
3634
3635     TRACE("Converting %ux%u pixels, pitches %u %u.\n", w, h, pitch_in, pitch_out);
3636
3637     for (y = 0; y < h; ++y)
3638     {
3639         const BYTE *src_line = src + y * pitch_in;
3640         DWORD *dst_line = (DWORD *)(dst + y * pitch_out);
3641         for (x = 0; x < w; ++x)
3642         {
3643             /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3644              *     C = Y - 16; D = U - 128; E = V - 128;
3645              *     R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3646              *     G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3647              *     B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3648              * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3649              * U and V are shared between the pixels. */
3650             if (!(x & 1)) /* For every even pixel, read new U and V. */
3651             {
3652                 d = (int) src_line[1] - 128;
3653                 e = (int) src_line[3] - 128;
3654                 r2 = 409 * e + 128;
3655                 g2 = - 100 * d - 208 * e + 128;
3656                 b2 = 516 * d + 128;
3657             }
3658             c2 = 298 * ((int) src_line[0] - 16);
3659             dst_line[x] = 0xff000000
3660                 | cliptobyte((c2 + r2) >> 8) << 16    /* red   */
3661                 | cliptobyte((c2 + g2) >> 8) << 8     /* green */
3662                 | cliptobyte((c2 + b2) >> 8);         /* blue  */
3663                 /* Scale RGB values to 0..255 range,
3664                  * then clip them if still not in range (may be negative),
3665                  * then shift them within DWORD if necessary. */
3666             src_line += 2;
3667         }
3668     }
3669 }
3670
3671 static void convert_yuy2_r5g6b5(const BYTE *src, BYTE *dst,
3672         DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h)
3673 {
3674     unsigned int x, y;
3675     int c2, d, e, r2 = 0, g2 = 0, b2 = 0;
3676
3677     TRACE("Converting %ux%u pixels, pitches %u %u\n", w, h, pitch_in, pitch_out);
3678
3679     for (y = 0; y < h; ++y)
3680     {
3681         const BYTE *src_line = src + y * pitch_in;
3682         WORD *dst_line = (WORD *)(dst + y * pitch_out);
3683         for (x = 0; x < w; ++x)
3684         {
3685             /* YUV to RGB conversion formulas from http://en.wikipedia.org/wiki/YUV:
3686              *     C = Y - 16; D = U - 128; E = V - 128;
3687              *     R = cliptobyte((298 * C + 409 * E + 128) >> 8);
3688              *     G = cliptobyte((298 * C - 100 * D - 208 * E + 128) >> 8);
3689              *     B = cliptobyte((298 * C + 516 * D + 128) >> 8);
3690              * Two adjacent YUY2 pixels are stored as four bytes: Y0 U Y1 V .
3691              * U and V are shared between the pixels. */
3692             if (!(x & 1)) /* For every even pixel, read new U and V. */
3693             {
3694                 d = (int) src_line[1] - 128;
3695                 e = (int) src_line[3] - 128;
3696                 r2 = 409 * e + 128;
3697                 g2 = - 100 * d - 208 * e + 128;
3698                 b2 = 516 * d + 128;
3699             }
3700             c2 = 298 * ((int) src_line[0] - 16);
3701             dst_line[x] = (cliptobyte((c2 + r2) >> 8) >> 3) << 11   /* red   */
3702                 | (cliptobyte((c2 + g2) >> 8) >> 2) << 5            /* green */
3703                 | (cliptobyte((c2 + b2) >> 8) >> 3);                /* blue  */
3704                 /* Scale RGB values to 0..255 range,
3705                  * then clip them if still not in range (may be negative),
3706                  * then shift them within DWORD if necessary. */
3707             src_line += 2;
3708         }
3709     }
3710 }
3711
3712 struct d3dfmt_converter_desc
3713 {
3714     enum wined3d_format_id from, to;
3715     void (*convert)(const BYTE *src, BYTE *dst, DWORD pitch_in, DWORD pitch_out, unsigned int w, unsigned int h);
3716 };
3717
3718 static const struct d3dfmt_converter_desc converters[] =
3719 {
3720     {WINED3DFMT_R32_FLOAT,      WINED3DFMT_R16_FLOAT,       convert_r32_float_r16_float},
3721     {WINED3DFMT_B5G6R5_UNORM,   WINED3DFMT_B8G8R8X8_UNORM,  convert_r5g6b5_x8r8g8b8},
3722     {WINED3DFMT_B8G8R8A8_UNORM, WINED3DFMT_B8G8R8X8_UNORM,  convert_a8r8g8b8_x8r8g8b8},
3723     {WINED3DFMT_B8G8R8X8_UNORM, WINED3DFMT_B8G8R8A8_UNORM,  convert_a8r8g8b8_x8r8g8b8},
3724     {WINED3DFMT_YUY2,           WINED3DFMT_B8G8R8X8_UNORM,  convert_yuy2_x8r8g8b8},
3725     {WINED3DFMT_YUY2,           WINED3DFMT_B5G6R5_UNORM,    convert_yuy2_r5g6b5},
3726 };
3727
3728 static inline const struct d3dfmt_converter_desc *find_converter(enum wined3d_format_id from,
3729         enum wined3d_format_id to)
3730 {
3731     unsigned int i;
3732
3733     for (i = 0; i < (sizeof(converters) / sizeof(*converters)); ++i)
3734     {
3735         if (converters[i].from == from && converters[i].to == to)
3736             return &converters[i];
3737     }
3738
3739     return NULL;
3740 }
3741
3742 /*****************************************************************************
3743  * surface_convert_format
3744  *
3745  * Creates a duplicate of a surface in a different format. Is used by Blt to
3746  * blit between surfaces with different formats.
3747  *
3748  * Parameters
3749  *  source: Source surface
3750  *  fmt: Requested destination format
3751  *
3752  *****************************************************************************/
3753 static struct wined3d_surface *surface_convert_format(struct wined3d_surface *source, enum wined3d_format_id to_fmt)
3754 {
3755     struct wined3d_map_desc src_map, dst_map;
3756     const struct d3dfmt_converter_desc *conv;
3757     struct wined3d_surface *ret = NULL;
3758     HRESULT hr;
3759
3760     conv = find_converter(source->resource.format->id, to_fmt);
3761     if (!conv)
3762     {
3763         FIXME("Cannot find a conversion function from format %s to %s.\n",
3764                 debug_d3dformat(source->resource.format->id), debug_d3dformat(to_fmt));
3765         return NULL;
3766     }
3767
3768     /* FIXME: Multisampled conversion? */
3769     if (FAILED(hr = wined3d_surface_create(source->resource.device, source->resource.width, source->resource.height,
3770             to_fmt, 0, WINED3D_POOL_SCRATCH, WINED3D_MULTISAMPLE_NONE, 0, source->surface_type,
3771             WINED3D_SURFACE_MAPPABLE | WINED3D_SURFACE_DISCARD, NULL, &wined3d_null_parent_ops, &ret)))
3772     {
3773         ERR("Failed to create a destination surface for conversion.\n");
3774         return NULL;
3775     }
3776
3777     memset(&src_map, 0, sizeof(src_map));
3778     memset(&dst_map, 0, sizeof(dst_map));
3779
3780     if (FAILED(hr = wined3d_surface_map(source, &src_map, NULL, WINED3D_MAP_READONLY)))
3781     {
3782         ERR("Failed to lock the source surface.\n");
3783         wined3d_surface_decref(ret);
3784         return NULL;
3785     }
3786     if (FAILED(hr = wined3d_surface_map(ret, &dst_map, NULL, WINED3D_MAP_READONLY)))
3787     {
3788         ERR("Failed to lock the destination surface.\n");
3789         wined3d_surface_unmap(source);
3790         wined3d_surface_decref(ret);
3791         return NULL;
3792     }
3793
3794     conv->convert(src_map.data, dst_map.data, src_map.row_pitch, dst_map.row_pitch,
3795             source->resource.width, source->resource.height);
3796
3797     wined3d_surface_unmap(ret);
3798     wined3d_surface_unmap(source);
3799
3800     return ret;
3801 }
3802
3803 static HRESULT _Blt_ColorFill(BYTE *buf, unsigned int width, unsigned int height,
3804         unsigned int bpp, UINT pitch, DWORD color)
3805 {
3806     BYTE *first;
3807     int x, y;
3808
3809     /* Do first row */
3810
3811 #define COLORFILL_ROW(type) \
3812 do { \
3813     type *d = (type *)buf; \
3814     for (x = 0; x < width; ++x) \
3815         d[x] = (type)color; \
3816 } while(0)
3817
3818     switch (bpp)
3819     {
3820         case 1:
3821             COLORFILL_ROW(BYTE);
3822             break;
3823
3824         case 2:
3825             COLORFILL_ROW(WORD);
3826             break;
3827
3828         case 3:
3829         {
3830             BYTE *d = buf;
3831             for (x = 0; x < width; ++x, d += 3)
3832             {
3833                 d[0] = (color      ) & 0xff;
3834                 d[1] = (color >>  8) & 0xff;
3835                 d[2] = (color >> 16) & 0xff;
3836             }
3837             break;
3838         }
3839         case 4:
3840             COLORFILL_ROW(DWORD);
3841             break;
3842
3843         default:
3844             FIXME("Color fill not implemented for bpp %u!\n", bpp * 8);
3845             return WINED3DERR_NOTAVAILABLE;
3846     }
3847
3848 #undef COLORFILL_ROW
3849
3850     /* Now copy first row. */
3851     first = buf;
3852     for (y = 1; y < height; ++y)
3853     {
3854         buf += pitch;
3855         memcpy(buf, first, width * bpp);
3856     }
3857
3858     return WINED3D_OK;
3859 }
3860
3861 struct wined3d_surface * CDECL wined3d_surface_from_resource(struct wined3d_resource *resource)
3862 {
3863     return surface_from_resource(resource);
3864 }
3865
3866 HRESULT CDECL wined3d_surface_unmap(struct wined3d_surface *surface)
3867 {
3868     TRACE("surface %p.\n", surface);
3869
3870     if (!surface->resource.map_count)
3871     {
3872         WARN("Trying to unmap unmapped surface.\n");
3873         return WINEDDERR_NOTLOCKED;
3874     }
3875     --surface->resource.map_count;
3876
3877     surface->surface_ops->surface_unmap(surface);
3878
3879     return WINED3D_OK;
3880 }
3881
3882 HRESULT CDECL wined3d_surface_map(struct wined3d_surface *surface,
3883         struct wined3d_map_desc *map_desc, const RECT *rect, DWORD flags)
3884 {
3885     const struct wined3d_format *format = surface->resource.format;
3886
3887     TRACE("surface %p, map_desc %p, rect %s, flags %#x.\n",
3888             surface, map_desc, wine_dbgstr_rect(rect), flags);
3889
3890     if (surface->resource.map_count)
3891     {
3892         WARN("Surface is already mapped.\n");
3893         return WINED3DERR_INVALIDCALL;
3894     }
3895
3896     if ((format->flags & WINED3DFMT_FLAG_BLOCKS) && rect
3897             && !surface_check_block_align(surface, rect))
3898     {
3899         WARN("Map rect %s is misaligned for %ux%u blocks.\n",
3900                 wine_dbgstr_rect(rect), format->block_width, format->block_height);
3901
3902         if (surface->resource.pool == WINED3D_POOL_DEFAULT)
3903             return WINED3DERR_INVALIDCALL;
3904     }
3905
3906     ++surface->resource.map_count;
3907
3908     if (!(surface->flags & SFLAG_LOCKABLE))
3909         WARN("Trying to lock unlockable surface.\n");
3910
3911     /* Performance optimization: Count how often a surface is mapped, if it is
3912      * mapped regularly do not throw away the system memory copy. This avoids
3913      * the need to download the surface from OpenGL all the time. The surface
3914      * is still downloaded if the OpenGL texture is changed. */
3915     if (!(surface->flags & SFLAG_DYNLOCK))
3916     {
3917         if (++surface->lockCount > MAXLOCKCOUNT)
3918         {
3919             TRACE("Surface is mapped regularly, not freeing the system memory copy any more.\n");
3920             surface->flags |= SFLAG_DYNLOCK;
3921         }
3922     }
3923
3924     surface->surface_ops->surface_map(surface, rect, flags);
3925
3926     if (format->flags & WINED3DFMT_FLAG_BROKEN_PITCH)
3927         map_desc->row_pitch = surface->resource.width * format->byte_count;
3928     else
3929         map_desc->row_pitch = wined3d_surface_get_pitch(surface);
3930     map_desc->slice_pitch = 0;
3931
3932     if (!rect)
3933     {
3934         map_desc->data = surface->resource.allocatedMemory;
3935         surface->lockedRect.left = 0;
3936         surface->lockedRect.top = 0;
3937         surface->lockedRect.right = surface->resource.width;
3938         surface->lockedRect.bottom = surface->resource.height;
3939     }
3940     else
3941     {
3942         if ((format->flags & (WINED3DFMT_FLAG_BLOCKS | WINED3DFMT_FLAG_BROKEN_PITCH)) == WINED3DFMT_FLAG_BLOCKS)
3943         {
3944             /* Compressed textures are block based, so calculate the offset of
3945              * the block that contains the top-left pixel of the locked rectangle. */
3946             map_desc->data = surface->resource.allocatedMemory
3947                     + ((rect->top / format->block_height) * map_desc->row_pitch)
3948                     + ((rect->left / format->block_width) * format->block_byte_count);
3949         }
3950         else
3951         {
3952             map_desc->data = surface->resource.allocatedMemory
3953                     + (map_desc->row_pitch * rect->top)
3954                     + (rect->left * format->byte_count);
3955         }
3956         surface->lockedRect.left = rect->left;
3957         surface->lockedRect.top = rect->top;
3958         surface->lockedRect.right = rect->right;
3959         surface->lockedRect.bottom = rect->bottom;
3960     }
3961
3962     TRACE("Locked rect %s.\n", wine_dbgstr_rect(&surface->lockedRect));
3963     TRACE("Returning memory %p, pitch %u.\n", map_desc->data, map_desc->row_pitch);
3964
3965     return WINED3D_OK;
3966 }
3967
3968 HRESULT CDECL wined3d_surface_getdc(struct wined3d_surface *surface, HDC *dc)
3969 {
3970     struct wined3d_map_desc map;
3971     HRESULT hr;
3972
3973     TRACE("surface %p, dc %p.\n", surface, dc);
3974
3975     if (surface->flags & SFLAG_USERPTR)
3976     {
3977         ERR("Not supported on surfaces with application-provided memory.\n");
3978         return WINEDDERR_NODC;
3979     }
3980
3981     /* Give more detailed info for ddraw. */
3982     if (surface->flags & SFLAG_DCINUSE)
3983         return WINEDDERR_DCALREADYCREATED;
3984
3985     /* Can't GetDC if the surface is locked. */
3986     if (surface->resource.map_count)
3987         return WINED3DERR_INVALIDCALL;
3988
3989     /* Create a DIB section if there isn't a dc yet. */
3990     if (!surface->hDC)
3991     {
3992         if (surface->flags & SFLAG_CLIENT)
3993         {
3994             surface_load_location(surface, SFLAG_INSYSMEM, NULL);
3995             surface_release_client_storage(surface);
3996         }
3997         hr = surface_create_dib_section(surface);
3998         if (FAILED(hr))
3999             return WINED3DERR_INVALIDCALL;
4000
4001         /* Use the DIB section from now on if we are not using a PBO. */
4002         if (!(surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)))
4003         {
4004             HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
4005             surface->resource.heapMemory = NULL;
4006             surface->resource.allocatedMemory = surface->dib.bitmap_data;
4007         }
4008     }
4009
4010     /* Map the surface. */
4011     hr = wined3d_surface_map(surface, &map, NULL, 0);
4012     if (FAILED(hr))
4013     {
4014         ERR("Map failed, hr %#x.\n", hr);
4015         return hr;
4016     }
4017
4018     /* Sync the DIB with the PBO. This can't be done earlier because Map()
4019      * activates the allocatedMemory. */
4020     if (surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM))
4021         memcpy(surface->dib.bitmap_data, surface->resource.allocatedMemory, surface->resource.size);
4022
4023     if (surface->resource.format->id == WINED3DFMT_P8_UINT
4024             || surface->resource.format->id == WINED3DFMT_P8_UINT_A8_UNORM)
4025     {
4026         /* GetDC on palettized formats is unsupported in D3D9, and the method
4027          * is missing in D3D8, so this should only be used for DX <=7
4028          * surfaces (with non-device palettes). */
4029         const PALETTEENTRY *pal = NULL;
4030
4031         if (surface->palette)
4032         {
4033             pal = surface->palette->palents;
4034         }
4035         else
4036         {
4037             struct wined3d_swapchain *swapchain = surface->resource.device->swapchains[0];
4038             struct wined3d_surface *dds_primary = swapchain->front_buffer;
4039
4040             if (dds_primary && dds_primary->palette)
4041                 pal = dds_primary->palette->palents;
4042         }
4043
4044         if (pal)
4045         {
4046             RGBQUAD col[256];
4047             unsigned int i;
4048
4049             for (i = 0; i < 256; ++i)
4050             {
4051                 col[i].rgbRed = pal[i].peRed;
4052                 col[i].rgbGreen = pal[i].peGreen;
4053                 col[i].rgbBlue = pal[i].peBlue;
4054                 col[i].rgbReserved = 0;
4055             }
4056             SetDIBColorTable(surface->hDC, 0, 256, col);
4057         }
4058     }
4059
4060     surface->flags |= SFLAG_DCINUSE;
4061
4062     *dc = surface->hDC;
4063     TRACE("Returning dc %p.\n", *dc);
4064
4065     return WINED3D_OK;
4066 }
4067
4068 HRESULT CDECL wined3d_surface_releasedc(struct wined3d_surface *surface, HDC dc)
4069 {
4070     TRACE("surface %p, dc %p.\n", surface, dc);
4071
4072     if (!(surface->flags & SFLAG_DCINUSE))
4073         return WINEDDERR_NODC;
4074
4075     if (surface->hDC != dc)
4076     {
4077         WARN("Application tries to release invalid DC %p, surface DC is %p.\n",
4078                 dc, surface->hDC);
4079         return WINEDDERR_NODC;
4080     }
4081
4082     /* Copy the contents of the DIB over to the PBO. */
4083     if ((surface->flags & (SFLAG_PBO | SFLAG_PIN_SYSMEM)) && surface->resource.allocatedMemory)
4084         memcpy(surface->resource.allocatedMemory, surface->dib.bitmap_data, surface->resource.size);
4085
4086     /* We locked first, so unlock now. */
4087     wined3d_surface_unmap(surface);
4088
4089     surface->flags &= ~SFLAG_DCINUSE;
4090
4091     return WINED3D_OK;
4092 }
4093
4094 HRESULT CDECL wined3d_surface_flip(struct wined3d_surface *surface, struct wined3d_surface *override, DWORD flags)
4095 {
4096     TRACE("surface %p, override %p, flags %#x.\n", surface, override, flags);
4097
4098     if (flags)
4099     {
4100         static UINT once;
4101         if (!once++)
4102             FIXME("Ignoring flags %#x.\n", flags);
4103         else
4104             WARN("Ignoring flags %#x.\n", flags);
4105     }
4106
4107     if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
4108     {
4109         ERR("Not supported on swapchain surfaces.\n");
4110         return WINEDDERR_NOTFLIPPABLE;
4111     }
4112
4113     /* Flipping is only supported on render targets and overlays. */
4114     if (!(surface->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)))
4115     {
4116         WARN("Tried to flip a non-render target, non-overlay surface.\n");
4117         return WINEDDERR_NOTFLIPPABLE;
4118     }
4119
4120     flip_surface(surface, override);
4121
4122     /* Update overlays if they're visible. */
4123     if ((surface->resource.usage & WINED3DUSAGE_OVERLAY) && surface->overlay_dest)
4124         return surface_draw_overlay(surface);
4125
4126     return WINED3D_OK;
4127 }
4128
4129 /* Do not call while under the GL lock. */
4130 void surface_internal_preload(struct wined3d_surface *surface, enum WINED3DSRGB srgb)
4131 {
4132     struct wined3d_device *device = surface->resource.device;
4133
4134     TRACE("iface %p, srgb %#x.\n", surface, srgb);
4135
4136     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4137     {
4138         struct wined3d_texture *texture = surface->container.u.texture;
4139
4140         TRACE("Passing to container (%p).\n", texture);
4141         texture->texture_ops->texture_preload(texture, srgb);
4142     }
4143     else
4144     {
4145         struct wined3d_context *context;
4146
4147         TRACE("(%p) : About to load surface\n", surface);
4148
4149         /* TODO: Use already acquired context when possible. */
4150         context = context_acquire(device, NULL);
4151
4152         surface_load(surface, srgb == SRGB_SRGB);
4153
4154         if (surface->resource.pool == WINED3D_POOL_DEFAULT)
4155         {
4156             /* Tell opengl to try and keep this texture in video ram (well mostly) */
4157             GLclampf tmp;
4158             tmp = 0.9f;
4159             ENTER_GL();
4160             context->gl_info->gl_ops.gl.p_glPrioritizeTextures(1, &surface->texture_name, &tmp);
4161             LEAVE_GL();
4162         }
4163
4164         context_release(context);
4165     }
4166 }
4167
4168 /* Read the framebuffer back into the surface */
4169 static void read_from_framebuffer(struct wined3d_surface *surface, const RECT *rect, void *dest, UINT pitch)
4170 {
4171     struct wined3d_device *device = surface->resource.device;
4172     const struct wined3d_gl_info *gl_info;
4173     struct wined3d_context *context;
4174     BYTE *mem;
4175     GLint fmt;
4176     GLint type;
4177     BYTE *row, *top, *bottom;
4178     int i;
4179     BOOL bpp;
4180     RECT local_rect;
4181     BOOL srcIsUpsideDown;
4182     GLint rowLen = 0;
4183     GLint skipPix = 0;
4184     GLint skipRow = 0;
4185
4186     context = context_acquire(device, surface);
4187     context_apply_blit_state(context, device);
4188     gl_info = context->gl_info;
4189
4190     ENTER_GL();
4191
4192     /* Select the correct read buffer, and give some debug output.
4193      * There is no need to keep track of the current read buffer or reset it, every part of the code
4194      * that reads sets the read buffer as desired.
4195      */
4196     if (surface_is_offscreen(surface))
4197     {
4198         /* Mapping the primary render target which is not on a swapchain.
4199          * Read from the back buffer. */
4200         TRACE("Mapping offscreen render target.\n");
4201         gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4202         srcIsUpsideDown = TRUE;
4203     }
4204     else
4205     {
4206         /* Onscreen surfaces are always part of a swapchain */
4207         GLenum buffer = surface_get_gl_buffer(surface);
4208         TRACE("Mapping %#x buffer.\n", buffer);
4209         gl_info->gl_ops.gl.p_glReadBuffer(buffer);
4210         checkGLcall("glReadBuffer");
4211         srcIsUpsideDown = FALSE;
4212     }
4213
4214     /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
4215     if (!rect)
4216     {
4217         local_rect.left = 0;
4218         local_rect.top = 0;
4219         local_rect.right = surface->resource.width;
4220         local_rect.bottom = surface->resource.height;
4221     }
4222     else
4223     {
4224         local_rect = *rect;
4225     }
4226     /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
4227
4228     switch (surface->resource.format->id)
4229     {
4230         case WINED3DFMT_P8_UINT:
4231         {
4232             if (primary_render_target_is_p8(device))
4233             {
4234                 /* In case of P8 render targets the index is stored in the alpha component */
4235                 fmt = GL_ALPHA;
4236                 type = GL_UNSIGNED_BYTE;
4237                 mem = dest;
4238                 bpp = surface->resource.format->byte_count;
4239             }
4240             else
4241             {
4242                 /* GL can't return palettized data, so read ARGB pixels into a
4243                  * separate block of memory and convert them into palettized format
4244                  * in software. Slow, but if the app means to use palettized render
4245                  * targets and locks it...
4246                  *
4247                  * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
4248                  * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
4249                  * for the color channels when palettizing the colors.
4250                  */
4251                 fmt = GL_RGB;
4252                 type = GL_UNSIGNED_BYTE;
4253                 pitch *= 3;
4254                 mem = HeapAlloc(GetProcessHeap(), 0, surface->resource.size * 3);
4255                 if (!mem)
4256                 {
4257                     ERR("Out of memory\n");
4258                     LEAVE_GL();
4259                     return;
4260                 }
4261                 bpp = surface->resource.format->byte_count * 3;
4262             }
4263         }
4264         break;
4265
4266         default:
4267             mem = dest;
4268             fmt = surface->resource.format->glFormat;
4269             type = surface->resource.format->glType;
4270             bpp = surface->resource.format->byte_count;
4271     }
4272
4273     if (surface->flags & SFLAG_PBO)
4274     {
4275         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, surface->pbo));
4276         checkGLcall("glBindBufferARB");
4277         if (mem)
4278         {
4279             ERR("mem not null for pbo -- unexpected\n");
4280             mem = NULL;
4281         }
4282     }
4283
4284     /* Save old pixel store pack state */
4285     gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
4286     checkGLcall("glGetIntegerv");
4287     gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
4288     checkGLcall("glGetIntegerv");
4289     gl_info->gl_ops.gl.p_glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
4290     checkGLcall("glGetIntegerv");
4291
4292     /* Setup pixel store pack state -- to glReadPixels into the correct place */
4293     gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, surface->resource.width);
4294     checkGLcall("glPixelStorei");
4295     gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
4296     checkGLcall("glPixelStorei");
4297     gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
4298     checkGLcall("glPixelStorei");
4299
4300     gl_info->gl_ops.gl.p_glReadPixels(local_rect.left,
4301             !srcIsUpsideDown ? (surface->resource.height - local_rect.bottom) : local_rect.top,
4302             local_rect.right - local_rect.left,
4303             local_rect.bottom - local_rect.top,
4304             fmt, type, mem);
4305     checkGLcall("glReadPixels");
4306
4307     /* Reset previous pixel store pack state */
4308     gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
4309     checkGLcall("glPixelStorei");
4310     gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
4311     checkGLcall("glPixelStorei");
4312     gl_info->gl_ops.gl.p_glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
4313     checkGLcall("glPixelStorei");
4314
4315     if (surface->flags & SFLAG_PBO)
4316     {
4317         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
4318         checkGLcall("glBindBufferARB");
4319
4320         /* Check if we need to flip the image. If we need to flip use glMapBufferARB
4321          * to get a pointer to it and perform the flipping in software. This is a lot
4322          * faster than calling glReadPixels for each line. In case we want more speed
4323          * we should rerender it flipped in a FBO and read the data back from the FBO. */
4324         if (!srcIsUpsideDown)
4325         {
4326             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4327             checkGLcall("glBindBufferARB");
4328
4329             mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
4330             checkGLcall("glMapBufferARB");
4331         }
4332     }
4333
4334     /* TODO: Merge this with the palettization loop below for P8 targets */
4335     if(!srcIsUpsideDown) {
4336         UINT len, off;
4337         /* glReadPixels returns the image upside down, and there is no way to prevent this.
4338             Flip the lines in software */
4339         len = (local_rect.right - local_rect.left) * bpp;
4340         off = local_rect.left * bpp;
4341
4342         row = HeapAlloc(GetProcessHeap(), 0, len);
4343         if(!row) {
4344             ERR("Out of memory\n");
4345             if (surface->resource.format->id == WINED3DFMT_P8_UINT)
4346                 HeapFree(GetProcessHeap(), 0, mem);
4347             LEAVE_GL();
4348             return;
4349         }
4350
4351         top = mem + pitch * local_rect.top;
4352         bottom = mem + pitch * (local_rect.bottom - 1);
4353         for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
4354             memcpy(row, top + off, len);
4355             memcpy(top + off, bottom + off, len);
4356             memcpy(bottom + off, row, len);
4357             top += pitch;
4358             bottom -= pitch;
4359         }
4360         HeapFree(GetProcessHeap(), 0, row);
4361
4362         /* Unmap the temp PBO buffer */
4363         if (surface->flags & SFLAG_PBO)
4364         {
4365             GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
4366             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4367         }
4368     }
4369
4370     LEAVE_GL();
4371     context_release(context);
4372
4373     /* For P8 textures we need to perform an inverse palette lookup. This is
4374      * done by searching for a palette index which matches the RGB value.
4375      * Note this isn't guaranteed to work when there are multiple entries for
4376      * the same color but we have no choice. In case of P8 render targets,
4377      * the index is stored in the alpha component so no conversion is needed. */
4378     if (surface->resource.format->id == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(device))
4379     {
4380         const PALETTEENTRY *pal = NULL;
4381         DWORD width = pitch / 3;
4382         int x, y, c;
4383
4384         if (surface->palette)
4385         {
4386             pal = surface->palette->palents;
4387         }
4388         else
4389         {
4390             ERR("Palette is missing, cannot perform inverse palette lookup\n");
4391             HeapFree(GetProcessHeap(), 0, mem);
4392             return;
4393         }
4394
4395         for(y = local_rect.top; y < local_rect.bottom; y++) {
4396             for(x = local_rect.left; x < local_rect.right; x++) {
4397                 /*                      start              lines            pixels      */
4398                 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
4399                 const BYTE *green = blue  + 1;
4400                 const BYTE *red = green + 1;
4401
4402                 for(c = 0; c < 256; c++) {
4403                     if(*red   == pal[c].peRed   &&
4404                        *green == pal[c].peGreen &&
4405                        *blue  == pal[c].peBlue)
4406                     {
4407                         *((BYTE *) dest + y * width + x) = c;
4408                         break;
4409                     }
4410                 }
4411             }
4412         }
4413         HeapFree(GetProcessHeap(), 0, mem);
4414     }
4415 }
4416
4417 /* Read the framebuffer contents into a texture. Note that this function
4418  * doesn't do any kind of flipping. Using this on an onscreen surface will
4419  * result in a flipped D3D texture. */
4420 void surface_load_fb_texture(struct wined3d_surface *surface, BOOL srgb)
4421 {
4422     struct wined3d_device *device = surface->resource.device;
4423     const struct wined3d_gl_info *gl_info;
4424     struct wined3d_context *context;
4425
4426     context = context_acquire(device, surface);
4427     gl_info = context->gl_info;
4428     device_invalidate_state(device, STATE_FRAMEBUFFER);
4429
4430     surface_prepare_texture(surface, context, srgb);
4431     surface_bind_and_dirtify(surface, context, srgb);
4432
4433     TRACE("Reading back offscreen render target %p.\n", surface);
4434
4435     ENTER_GL();
4436
4437     if (surface_is_offscreen(surface))
4438         gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4439     else
4440         gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(surface));
4441     checkGLcall("glReadBuffer");
4442
4443     gl_info->gl_ops.gl.p_glCopyTexSubImage2D(surface->texture_target, surface->texture_level,
4444             0, 0, 0, 0, surface->resource.width, surface->resource.height);
4445     checkGLcall("glCopyTexSubImage2D");
4446
4447     LEAVE_GL();
4448
4449     context_release(context);
4450 }
4451
4452 /* Context activation is done by the caller. */
4453 static void surface_prepare_texture_internal(struct wined3d_surface *surface,
4454         struct wined3d_context *context, BOOL srgb)
4455 {
4456     DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
4457     enum wined3d_conversion_type convert;
4458     struct wined3d_format format;
4459
4460     if (surface->flags & alloc_flag) return;
4461
4462     d3dfmt_get_conv(surface, TRUE, TRUE, &format, &convert);
4463     if (convert != WINED3D_CT_NONE || format.convert)
4464         surface->flags |= SFLAG_CONVERTED;
4465     else surface->flags &= ~SFLAG_CONVERTED;
4466
4467     surface_bind_and_dirtify(surface, context, srgb);
4468     surface_allocate_surface(surface, context->gl_info, &format, srgb);
4469     surface->flags |= alloc_flag;
4470 }
4471
4472 /* Context activation is done by the caller. */
4473 void surface_prepare_texture(struct wined3d_surface *surface, struct wined3d_context *context, BOOL srgb)
4474 {
4475     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
4476     {
4477         struct wined3d_texture *texture = surface->container.u.texture;
4478         UINT sub_count = texture->level_count * texture->layer_count;
4479         UINT i;
4480
4481         TRACE("surface %p is a subresource of texture %p.\n", surface, texture);
4482
4483         for (i = 0; i < sub_count; ++i)
4484         {
4485             struct wined3d_surface *s = surface_from_resource(texture->sub_resources[i]);
4486             surface_prepare_texture_internal(s, context, srgb);
4487         }
4488
4489         return;
4490     }
4491
4492     surface_prepare_texture_internal(surface, context, srgb);
4493 }
4494
4495 void surface_prepare_rb(struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info, BOOL multisample)
4496 {
4497     if (multisample)
4498     {
4499         if (surface->rb_multisample)
4500             return;
4501
4502         gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_multisample);
4503         gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_multisample);
4504         gl_info->fbo_ops.glRenderbufferStorageMultisample(GL_RENDERBUFFER, surface->resource.multisample_type,
4505                 surface->resource.format->glInternal, surface->pow2Width, surface->pow2Height);
4506         TRACE("Created multisample rb %u.\n", surface->rb_multisample);
4507     }
4508     else
4509     {
4510         if (surface->rb_resolved)
4511             return;
4512
4513         gl_info->fbo_ops.glGenRenderbuffers(1, &surface->rb_resolved);
4514         gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, surface->rb_resolved);
4515         gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, surface->resource.format->glInternal,
4516                 surface->pow2Width, surface->pow2Height);
4517         TRACE("Created resolved rb %u.\n", surface->rb_resolved);
4518     }
4519 }
4520
4521 static void flush_to_framebuffer_drawpixels(struct wined3d_surface *surface,
4522         const RECT *rect, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem)
4523 {
4524     struct wined3d_device *device = surface->resource.device;
4525     UINT pitch = wined3d_surface_get_pitch(surface);
4526     const struct wined3d_gl_info *gl_info;
4527     struct wined3d_context *context;
4528     RECT local_rect;
4529     UINT w, h;
4530
4531     surface_get_rect(surface, rect, &local_rect);
4532
4533     mem += local_rect.top * pitch + local_rect.left * bpp;
4534     w = local_rect.right - local_rect.left;
4535     h = local_rect.bottom - local_rect.top;
4536
4537     /* Activate the correct context for the render target */
4538     context = context_acquire(device, surface);
4539     context_apply_blit_state(context, device);
4540     gl_info = context->gl_info;
4541
4542     ENTER_GL();
4543
4544     if (!surface_is_offscreen(surface))
4545     {
4546         GLenum buffer = surface_get_gl_buffer(surface);
4547         TRACE("Unlocking %#x buffer.\n", buffer);
4548         context_set_draw_buffer(context, buffer);
4549
4550         surface_translate_drawable_coords(surface, context->win_handle, &local_rect);
4551         gl_info->gl_ops.gl.p_glPixelZoom(1.0f, -1.0f);
4552     }
4553     else
4554     {
4555         /* Primary offscreen render target */
4556         TRACE("Offscreen render target.\n");
4557         context_set_draw_buffer(context, device->offscreenBuffer);
4558
4559         gl_info->gl_ops.gl.p_glPixelZoom(1.0f, 1.0f);
4560     }
4561
4562     gl_info->gl_ops.gl.p_glRasterPos3i(local_rect.left, local_rect.top, 1);
4563     checkGLcall("glRasterPos3i");
4564
4565     /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
4566     gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, surface->resource.width);
4567
4568     if (surface->flags & SFLAG_PBO)
4569     {
4570         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, surface->pbo));
4571         checkGLcall("glBindBufferARB");
4572     }
4573
4574     gl_info->gl_ops.gl.p_glDrawPixels(w, h, fmt, type, mem);
4575     checkGLcall("glDrawPixels");
4576
4577     if (surface->flags & SFLAG_PBO)
4578     {
4579         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
4580         checkGLcall("glBindBufferARB");
4581     }
4582
4583     gl_info->gl_ops.gl.p_glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
4584     checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH, 0)");
4585
4586     LEAVE_GL();
4587
4588     if (wined3d_settings.strict_draw_ordering
4589             || (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
4590             && surface->container.u.swapchain->front_buffer == surface))
4591         gl_info->gl_ops.gl.p_glFlush();
4592
4593     context_release(context);
4594 }
4595
4596 static BOOL color_in_range(const struct wined3d_color_key *color_key, DWORD color)
4597 {
4598     /* FIXME: Is this really how color keys are supposed to work? I think it
4599      * makes more sense to compare the individual channels. */
4600     return color >= color_key->color_space_low_value
4601             && color <= color_key->color_space_high_value;
4602 }
4603
4604 void d3dfmt_p8_init_palette(const struct wined3d_surface *surface, BYTE table[256][4], BOOL colorkey)
4605 {
4606     const struct wined3d_device *device = surface->resource.device;
4607     const struct wined3d_palette *pal = surface->palette;
4608     BOOL index_in_alpha = FALSE;
4609     unsigned int i;
4610
4611     /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
4612      * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
4613      * is slow. Further RGB->P8 conversion is not possible because palettes can have
4614      * duplicate entries. Store the color key in the unused alpha component to speed the
4615      * download up and to make conversion unneeded. */
4616     index_in_alpha = primary_render_target_is_p8(device);
4617
4618     if (!pal)
4619     {
4620         ERR("This code should never get entered for DirectDraw!, expect problems\n");
4621         if (index_in_alpha)
4622         {
4623             /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
4624              * there's no palette at this time. */
4625             for (i = 0; i < 256; i++) table[i][3] = i;
4626         }
4627     }
4628     else
4629     {
4630         TRACE("Using surface palette %p\n", pal);
4631         /* Get the surface's palette */
4632         for (i = 0; i < 256; ++i)
4633         {
4634             table[i][0] = pal->palents[i].peRed;
4635             table[i][1] = pal->palents[i].peGreen;
4636             table[i][2] = pal->palents[i].peBlue;
4637
4638             /* When index_in_alpha is set the palette index is stored in the
4639              * alpha component. In case of a readback we can then read
4640              * GL_ALPHA. Color keying is handled in BltOverride using a
4641              * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
4642              * color key itself is passed to glAlphaFunc in other cases the
4643              * alpha component of pixels that should be masked away is set to 0. */
4644             if (index_in_alpha)
4645                 table[i][3] = i;
4646             else if (colorkey && color_in_range(&surface->src_blt_color_key, i))
4647                 table[i][3] = 0x00;
4648             else if (pal->flags & WINEDDPCAPS_ALPHA)
4649                 table[i][3] = pal->palents[i].peFlags;
4650             else
4651                 table[i][3] = 0xff;
4652         }
4653     }
4654 }
4655
4656 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height,
4657         UINT outpitch, enum wined3d_conversion_type conversion_type, struct wined3d_surface *surface)
4658 {
4659     const BYTE *source;
4660     BYTE *dest;
4661
4662     TRACE("src %p, dst %p, pitch %u, width %u, height %u, outpitch %u, conversion_type %#x, surface %p.\n",
4663             src, dst, pitch, width, height, outpitch, conversion_type, surface);
4664
4665     switch (conversion_type)
4666     {
4667         case WINED3D_CT_NONE:
4668         {
4669             memcpy(dst, src, pitch * height);
4670             break;
4671         }
4672
4673         case WINED3D_CT_PALETTED:
4674         case WINED3D_CT_PALETTED_CK:
4675         {
4676             BYTE table[256][4];
4677             unsigned int x, y;
4678
4679             d3dfmt_p8_init_palette(surface, table, (conversion_type == WINED3D_CT_PALETTED_CK));
4680
4681             for (y = 0; y < height; y++)
4682             {
4683                 source = src + pitch * y;
4684                 dest = dst + outpitch * y;
4685                 /* This is an 1 bpp format, using the width here is fine */
4686                 for (x = 0; x < width; x++) {
4687                     BYTE color = *source++;
4688                     *dest++ = table[color][0];
4689                     *dest++ = table[color][1];
4690                     *dest++ = table[color][2];
4691                     *dest++ = table[color][3];
4692                 }
4693             }
4694         }
4695         break;
4696
4697         case WINED3D_CT_CK_565:
4698         {
4699             /* Converting the 565 format in 5551 packed to emulate color-keying.
4700
4701               Note : in all these conversion, it would be best to average the averaging
4702                       pixels to get the color of the pixel that will be color-keyed to
4703                       prevent 'color bleeding'. This will be done later on if ever it is
4704                       too visible.
4705
4706               Note2: Nvidia documents say that their driver does not support alpha + color keying
4707                      on the same surface and disables color keying in such a case
4708             */
4709             unsigned int x, y;
4710             const WORD *Source;
4711             WORD *Dest;
4712
4713             TRACE("Color keyed 565\n");
4714
4715             for (y = 0; y < height; y++) {
4716                 Source = (const WORD *)(src + y * pitch);
4717                 Dest = (WORD *) (dst + y * outpitch);
4718                 for (x = 0; x < width; x++ ) {
4719                     WORD color = *Source++;
4720                     *Dest = ((color & 0xffc0) | ((color & 0x1f) << 1));
4721                     if (!color_in_range(&surface->src_blt_color_key, color))
4722                         *Dest |= 0x0001;
4723                     Dest++;
4724                 }
4725             }
4726         }
4727         break;
4728
4729         case WINED3D_CT_CK_5551:
4730         {
4731             /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
4732             unsigned int x, y;
4733             const WORD *Source;
4734             WORD *Dest;
4735             TRACE("Color keyed 5551\n");
4736             for (y = 0; y < height; y++) {
4737                 Source = (const WORD *)(src + y * pitch);
4738                 Dest = (WORD *) (dst + y * outpitch);
4739                 for (x = 0; x < width; x++ ) {
4740                     WORD color = *Source++;
4741                     *Dest = color;
4742                     if (!color_in_range(&surface->src_blt_color_key, color))
4743                         *Dest |= (1 << 15);
4744                     else
4745                         *Dest &= ~(1 << 15);
4746                     Dest++;
4747                 }
4748             }
4749         }
4750         break;
4751
4752         case WINED3D_CT_CK_RGB24:
4753         {
4754             /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
4755             unsigned int x, y;
4756             for (y = 0; y < height; y++)
4757             {
4758                 source = src + pitch * y;
4759                 dest = dst + outpitch * y;
4760                 for (x = 0; x < width; x++) {
4761                     DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
4762                     DWORD dstcolor = color << 8;
4763                     if (!color_in_range(&surface->src_blt_color_key, color))
4764                         dstcolor |= 0xff;
4765                     *(DWORD*)dest = dstcolor;
4766                     source += 3;
4767                     dest += 4;
4768                 }
4769             }
4770         }
4771         break;
4772
4773         case WINED3D_CT_RGB32_888:
4774         {
4775             /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
4776             unsigned int x, y;
4777             for (y = 0; y < height; y++)
4778             {
4779                 source = src + pitch * y;
4780                 dest = dst + outpitch * y;
4781                 for (x = 0; x < width; x++) {
4782                     DWORD color = 0xffffff & *(const DWORD*)source;
4783                     DWORD dstcolor = color << 8;
4784                     if (!color_in_range(&surface->src_blt_color_key, color))
4785                         dstcolor |= 0xff;
4786                     *(DWORD*)dest = dstcolor;
4787                     source += 4;
4788                     dest += 4;
4789                 }
4790             }
4791         }
4792         break;
4793
4794         case WINED3D_CT_CK_ARGB32:
4795         {
4796             unsigned int x, y;
4797             for (y = 0; y < height; ++y)
4798             {
4799                 source = src + pitch * y;
4800                 dest = dst + outpitch * y;
4801                 for (x = 0; x < width; ++x)
4802                 {
4803                     DWORD color = *(const DWORD *)source;
4804                     if (color_in_range(&surface->src_blt_color_key, color))
4805                         color &= ~0xff000000;
4806                     *(DWORD*)dest = color;
4807                     source += 4;
4808                     dest += 4;
4809                 }
4810             }
4811         }
4812         break;
4813
4814         default:
4815             ERR("Unsupported conversion type %#x.\n", conversion_type);
4816     }
4817     return WINED3D_OK;
4818 }
4819
4820 void flip_surface(struct wined3d_surface *front, struct wined3d_surface *back)
4821 {
4822     /* Flip the surface contents */
4823     /* Flip the DC */
4824     {
4825         HDC tmp;
4826         tmp = front->hDC;
4827         front->hDC = back->hDC;
4828         back->hDC = tmp;
4829     }
4830
4831     /* Flip the DIBsection */
4832     {
4833         HBITMAP tmp = front->dib.DIBsection;
4834         front->dib.DIBsection = back->dib.DIBsection;
4835         back->dib.DIBsection = tmp;
4836     }
4837
4838     /* Flip the surface data */
4839     {
4840         void* tmp;
4841
4842         tmp = front->dib.bitmap_data;
4843         front->dib.bitmap_data = back->dib.bitmap_data;
4844         back->dib.bitmap_data = tmp;
4845
4846         tmp = front->resource.allocatedMemory;
4847         front->resource.allocatedMemory = back->resource.allocatedMemory;
4848         back->resource.allocatedMemory = tmp;
4849
4850         tmp = front->resource.heapMemory;
4851         front->resource.heapMemory = back->resource.heapMemory;
4852         back->resource.heapMemory = tmp;
4853     }
4854
4855     /* Flip the PBO */
4856     {
4857         GLuint tmp_pbo = front->pbo;
4858         front->pbo = back->pbo;
4859         back->pbo = tmp_pbo;
4860     }
4861
4862     /* Flip the opengl texture */
4863     {
4864         GLuint tmp;
4865
4866         tmp = back->texture_name;
4867         back->texture_name = front->texture_name;
4868         front->texture_name = tmp;
4869
4870         tmp = back->texture_name_srgb;
4871         back->texture_name_srgb = front->texture_name_srgb;
4872         front->texture_name_srgb = tmp;
4873
4874         tmp = back->rb_multisample;
4875         back->rb_multisample = front->rb_multisample;
4876         front->rb_multisample = tmp;
4877
4878         tmp = back->rb_resolved;
4879         back->rb_resolved = front->rb_resolved;
4880         front->rb_resolved = tmp;
4881
4882         resource_unload(&back->resource);
4883         resource_unload(&front->resource);
4884     }
4885
4886     {
4887         DWORD tmp_flags = back->flags;
4888         back->flags = front->flags;
4889         front->flags = tmp_flags;
4890     }
4891 }
4892
4893 /* Does a direct frame buffer -> texture copy. Stretching is done with single
4894  * pixel copy calls. */
4895 static void fb_copy_to_texture_direct(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
4896         const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
4897 {
4898     struct wined3d_device *device = dst_surface->resource.device;
4899     const struct wined3d_gl_info *gl_info;
4900     float xrel, yrel;
4901     UINT row;
4902     struct wined3d_context *context;
4903     BOOL upsidedown = FALSE;
4904     RECT dst_rect = *dst_rect_in;
4905     GLenum dst_target;
4906
4907     if (dst_surface->container.type == WINED3D_CONTAINER_TEXTURE)
4908         dst_target = dst_surface->container.u.texture->target;
4909     else
4910         dst_target = dst_surface->texture_target;
4911
4912     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
4913      * glCopyTexSubImage is a bit picky about the parameters we pass to it
4914      */
4915     if(dst_rect.top > dst_rect.bottom) {
4916         UINT tmp = dst_rect.bottom;
4917         dst_rect.bottom = dst_rect.top;
4918         dst_rect.top = tmp;
4919         upsidedown = TRUE;
4920     }
4921
4922     context = context_acquire(device, src_surface);
4923     gl_info = context->gl_info;
4924     context_apply_blit_state(context, device);
4925     surface_internal_preload(dst_surface, SRGB_RGB);
4926     ENTER_GL();
4927
4928     /* Bind the target texture */
4929     context_bind_texture(context, dst_target, dst_surface->texture_name);
4930     if (surface_is_offscreen(src_surface))
4931     {
4932         TRACE("Reading from an offscreen target\n");
4933         upsidedown = !upsidedown;
4934         gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
4935     }
4936     else
4937     {
4938         gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
4939     }
4940     checkGLcall("glReadBuffer");
4941
4942     xrel = (float) (src_rect->right - src_rect->left) / (float) (dst_rect.right - dst_rect.left);
4943     yrel = (float) (src_rect->bottom - src_rect->top) / (float) (dst_rect.bottom - dst_rect.top);
4944
4945     if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4946     {
4947         FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
4948
4949         if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4950             ERR("Texture filtering not supported in direct blit.\n");
4951     }
4952     else if ((filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT)
4953             && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4954     {
4955         ERR("Texture filtering not supported in direct blit\n");
4956     }
4957
4958     if (upsidedown
4959             && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4960             && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
4961     {
4962         /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do. */
4963         gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4964                 dst_rect.left /*xoffset */, dst_rect.top /* y offset */,
4965                 src_rect->left, src_surface->resource.height - src_rect->bottom,
4966                 dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
4967     }
4968     else
4969     {
4970         UINT yoffset = src_surface->resource.height - src_rect->top + dst_rect.top - 1;
4971         /* I have to process this row by row to swap the image,
4972          * otherwise it would be upside down, so stretching in y direction
4973          * doesn't cost extra time
4974          *
4975          * However, stretching in x direction can be avoided if not necessary
4976          */
4977         for(row = dst_rect.top; row < dst_rect.bottom; row++) {
4978             if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
4979             {
4980                 /* Well, that stuff works, but it's very slow.
4981                  * find a better way instead
4982                  */
4983                 UINT col;
4984
4985                 for (col = dst_rect.left; col < dst_rect.right; ++col)
4986                 {
4987                     gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4988                             dst_rect.left + col /* x offset */, row /* y offset */,
4989                             src_rect->left + col * xrel, yoffset - (int) (row * yrel), 1, 1);
4990                 }
4991             }
4992             else
4993             {
4994                 gl_info->gl_ops.gl.p_glCopyTexSubImage2D(dst_surface->texture_target, dst_surface->texture_level,
4995                         dst_rect.left /* x offset */, row /* y offset */,
4996                         src_rect->left, yoffset - (int) (row * yrel), dst_rect.right - dst_rect.left, 1);
4997             }
4998         }
4999     }
5000     checkGLcall("glCopyTexSubImage2D");
5001
5002     LEAVE_GL();
5003     context_release(context);
5004
5005     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5006      * path is never entered
5007      */
5008     surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5009 }
5010
5011 /* Uses the hardware to stretch and flip the image */
5012 static void fb_copy_to_texture_hwstretch(struct wined3d_surface *dst_surface, struct wined3d_surface *src_surface,
5013         const RECT *src_rect, const RECT *dst_rect_in, enum wined3d_texture_filter_type filter)
5014 {
5015     struct wined3d_device *device = dst_surface->resource.device;
5016     struct wined3d_swapchain *src_swapchain = NULL;
5017     GLuint src, backup = 0;
5018     float left, right, top, bottom; /* Texture coordinates */
5019     UINT fbwidth = src_surface->resource.width;
5020     UINT fbheight = src_surface->resource.height;
5021     const struct wined3d_gl_info *gl_info;
5022     struct wined3d_context *context;
5023     GLenum drawBuffer = GL_BACK;
5024     GLenum texture_target;
5025     BOOL noBackBufferBackup;
5026     BOOL src_offscreen;
5027     BOOL upsidedown = FALSE;
5028     RECT dst_rect = *dst_rect_in;
5029
5030     TRACE("Using hwstretch blit\n");
5031     /* Activate the Proper context for reading from the source surface, set it up for blitting */
5032     context = context_acquire(device, src_surface);
5033     gl_info = context->gl_info;
5034     context_apply_blit_state(context, device);
5035     surface_internal_preload(dst_surface, SRGB_RGB);
5036
5037     src_offscreen = surface_is_offscreen(src_surface);
5038     noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
5039     if (!noBackBufferBackup && !src_surface->texture_name)
5040     {
5041         /* Get it a description */
5042         surface_internal_preload(src_surface, SRGB_RGB);
5043     }
5044     ENTER_GL();
5045
5046     /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
5047      * This way we don't have to wait for the 2nd readback to finish to leave this function.
5048      */
5049     if (context->aux_buffers >= 2)
5050     {
5051         /* Got more than one aux buffer? Use the 2nd aux buffer */
5052         drawBuffer = GL_AUX1;
5053     }
5054     else if ((!src_offscreen || device->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
5055     {
5056         /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
5057         drawBuffer = GL_AUX0;
5058     }
5059
5060     if (noBackBufferBackup)
5061     {
5062         gl_info->gl_ops.gl.p_glGenTextures(1, &backup);
5063         checkGLcall("glGenTextures");
5064         context_bind_texture(context, GL_TEXTURE_2D, backup);
5065         texture_target = GL_TEXTURE_2D;
5066     }
5067     else
5068     {
5069         /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
5070          * we are reading from the back buffer, the backup can be used as source texture
5071          */
5072         texture_target = src_surface->texture_target;
5073         context_bind_texture(context, texture_target, src_surface->texture_name);
5074         gl_info->gl_ops.gl.p_glEnable(texture_target);
5075         checkGLcall("glEnable(texture_target)");
5076
5077         /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
5078         src_surface->flags &= ~SFLAG_INTEXTURE;
5079     }
5080
5081     /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
5082      * glCopyTexSubImage is a bit picky about the parameters we pass to it
5083      */
5084     if(dst_rect.top > dst_rect.bottom) {
5085         UINT tmp = dst_rect.bottom;
5086         dst_rect.bottom = dst_rect.top;
5087         dst_rect.top = tmp;
5088         upsidedown = TRUE;
5089     }
5090
5091     if (src_offscreen)
5092     {
5093         TRACE("Reading from an offscreen target\n");
5094         upsidedown = !upsidedown;
5095         gl_info->gl_ops.gl.p_glReadBuffer(device->offscreenBuffer);
5096     }
5097     else
5098     {
5099         gl_info->gl_ops.gl.p_glReadBuffer(surface_get_gl_buffer(src_surface));
5100     }
5101
5102     /* TODO: Only back up the part that will be overwritten */
5103     gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target, 0, 0, 0, 0, 0, fbwidth, fbheight);
5104
5105     checkGLcall("glCopyTexSubImage2D");
5106
5107     /* No issue with overriding these - the sampler is dirty due to blit usage */
5108     gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
5109             wined3d_gl_mag_filter(magLookup, filter));
5110     checkGLcall("glTexParameteri");
5111     gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
5112             wined3d_gl_min_mip_filter(minMipLookup, filter, WINED3D_TEXF_NONE));
5113     checkGLcall("glTexParameteri");
5114
5115     if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5116         src_swapchain = src_surface->container.u.swapchain;
5117     if (!src_swapchain || src_surface == src_swapchain->back_buffers[0])
5118     {
5119         src = backup ? backup : src_surface->texture_name;
5120     }
5121     else
5122     {
5123         gl_info->gl_ops.gl.p_glReadBuffer(GL_FRONT);
5124         checkGLcall("glReadBuffer(GL_FRONT)");
5125
5126         gl_info->gl_ops.gl.p_glGenTextures(1, &src);
5127         checkGLcall("glGenTextures(1, &src)");
5128         context_bind_texture(context, GL_TEXTURE_2D, src);
5129
5130         /* TODO: Only copy the part that will be read. Use src_rect->left, src_rect->bottom as origin, but with the width watch
5131          * out for power of 2 sizes
5132          */
5133         gl_info->gl_ops.gl.p_glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, src_surface->pow2Width,
5134                 src_surface->pow2Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
5135         checkGLcall("glTexImage2D");
5136         gl_info->gl_ops.gl.p_glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, fbwidth, fbheight);
5137
5138         gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5139         checkGLcall("glTexParameteri");
5140         gl_info->gl_ops.gl.p_glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5141         checkGLcall("glTexParameteri");
5142
5143         gl_info->gl_ops.gl.p_glReadBuffer(GL_BACK);
5144         checkGLcall("glReadBuffer(GL_BACK)");
5145
5146         if (texture_target != GL_TEXTURE_2D)
5147         {
5148             gl_info->gl_ops.gl.p_glDisable(texture_target);
5149             gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5150             texture_target = GL_TEXTURE_2D;
5151         }
5152     }
5153     checkGLcall("glEnd and previous");
5154
5155     left = src_rect->left;
5156     right = src_rect->right;
5157
5158     if (!upsidedown)
5159     {
5160         top = src_surface->resource.height - src_rect->top;
5161         bottom = src_surface->resource.height - src_rect->bottom;
5162     }
5163     else
5164     {
5165         top = src_surface->resource.height - src_rect->bottom;
5166         bottom = src_surface->resource.height - src_rect->top;
5167     }
5168
5169     if (src_surface->flags & SFLAG_NORMCOORD)
5170     {
5171         left /= src_surface->pow2Width;
5172         right /= src_surface->pow2Width;
5173         top /= src_surface->pow2Height;
5174         bottom /= src_surface->pow2Height;
5175     }
5176
5177     /* draw the source texture stretched and upside down. The correct surface is bound already */
5178     gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
5179     gl_info->gl_ops.gl.p_glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
5180
5181     context_set_draw_buffer(context, drawBuffer);
5182     gl_info->gl_ops.gl.p_glReadBuffer(drawBuffer);
5183
5184     gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5185         /* bottom left */
5186         gl_info->gl_ops.gl.p_glTexCoord2f(left, bottom);
5187         gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5188
5189         /* top left */
5190         gl_info->gl_ops.gl.p_glTexCoord2f(left, top);
5191         gl_info->gl_ops.gl.p_glVertex2i(0, dst_rect.bottom - dst_rect.top);
5192
5193         /* top right */
5194         gl_info->gl_ops.gl.p_glTexCoord2f(right, top);
5195         gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5196
5197         /* bottom right */
5198         gl_info->gl_ops.gl.p_glTexCoord2f(right, bottom);
5199         gl_info->gl_ops.gl.p_glVertex2i(dst_rect.right - dst_rect.left, 0);
5200     gl_info->gl_ops.gl.p_glEnd();
5201     checkGLcall("glEnd and previous");
5202
5203     if (texture_target != dst_surface->texture_target)
5204     {
5205         gl_info->gl_ops.gl.p_glDisable(texture_target);
5206         gl_info->gl_ops.gl.p_glEnable(dst_surface->texture_target);
5207         texture_target = dst_surface->texture_target;
5208     }
5209
5210     /* Now read the stretched and upside down image into the destination texture */
5211     context_bind_texture(context, texture_target, dst_surface->texture_name);
5212     gl_info->gl_ops.gl.p_glCopyTexSubImage2D(texture_target,
5213                         0,
5214                         dst_rect.left, dst_rect.top, /* xoffset, yoffset */
5215                         0, 0, /* We blitted the image to the origin */
5216                         dst_rect.right - dst_rect.left, dst_rect.bottom - dst_rect.top);
5217     checkGLcall("glCopyTexSubImage2D");
5218
5219     if (drawBuffer == GL_BACK)
5220     {
5221         /* Write the back buffer backup back. */
5222         if (backup)
5223         {
5224             if (texture_target != GL_TEXTURE_2D)
5225             {
5226                 gl_info->gl_ops.gl.p_glDisable(texture_target);
5227                 gl_info->gl_ops.gl.p_glEnable(GL_TEXTURE_2D);
5228                 texture_target = GL_TEXTURE_2D;
5229             }
5230             context_bind_texture(context, GL_TEXTURE_2D, backup);
5231         }
5232         else
5233         {
5234             if (texture_target != src_surface->texture_target)
5235             {
5236                 gl_info->gl_ops.gl.p_glDisable(texture_target);
5237                 gl_info->gl_ops.gl.p_glEnable(src_surface->texture_target);
5238                 texture_target = src_surface->texture_target;
5239             }
5240             context_bind_texture(context, src_surface->texture_target, src_surface->texture_name);
5241         }
5242
5243         gl_info->gl_ops.gl.p_glBegin(GL_QUADS);
5244             /* top left */
5245             gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, 0.0f);
5246             gl_info->gl_ops.gl.p_glVertex2i(0, fbheight);
5247
5248             /* bottom left */
5249             gl_info->gl_ops.gl.p_glTexCoord2f(0.0f, (float)fbheight / (float)src_surface->pow2Height);
5250             gl_info->gl_ops.gl.p_glVertex2i(0, 0);
5251
5252             /* bottom right */
5253             gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width,
5254                     (float)fbheight / (float)src_surface->pow2Height);
5255             gl_info->gl_ops.gl.p_glVertex2i(fbwidth, 0);
5256
5257             /* top right */
5258             gl_info->gl_ops.gl.p_glTexCoord2f((float)fbwidth / (float)src_surface->pow2Width, 0.0f);
5259             gl_info->gl_ops.gl.p_glVertex2i(fbwidth, fbheight);
5260         gl_info->gl_ops.gl.p_glEnd();
5261     }
5262     gl_info->gl_ops.gl.p_glDisable(texture_target);
5263     checkGLcall("glDisable(texture_target)");
5264
5265     /* Cleanup */
5266     if (src != src_surface->texture_name && src != backup)
5267     {
5268         gl_info->gl_ops.gl.p_glDeleteTextures(1, &src);
5269         checkGLcall("glDeleteTextures(1, &src)");
5270     }
5271     if (backup)
5272     {
5273         gl_info->gl_ops.gl.p_glDeleteTextures(1, &backup);
5274         checkGLcall("glDeleteTextures(1, &backup)");
5275     }
5276
5277     LEAVE_GL();
5278
5279     if (wined3d_settings.strict_draw_ordering)
5280         gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5281
5282     context_release(context);
5283
5284     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
5285      * path is never entered
5286      */
5287     surface_modify_location(dst_surface, SFLAG_INTEXTURE, TRUE);
5288 }
5289
5290 /* Front buffer coordinates are always full screen coordinates, but our GL
5291  * drawable is limited to the window's client area. The sysmem and texture
5292  * copies do have the full screen size. Note that GL has a bottom-left
5293  * origin, while D3D has a top-left origin. */
5294 void surface_translate_drawable_coords(const struct wined3d_surface *surface, HWND window, RECT *rect)
5295 {
5296     UINT drawable_height;
5297
5298     if (surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5299             && surface == surface->container.u.swapchain->front_buffer)
5300     {
5301         POINT offset = {0, 0};
5302         RECT windowsize;
5303
5304         ScreenToClient(window, &offset);
5305         OffsetRect(rect, offset.x, offset.y);
5306
5307         GetClientRect(window, &windowsize);
5308         drawable_height = windowsize.bottom - windowsize.top;
5309     }
5310     else
5311     {
5312         drawable_height = surface->resource.height;
5313     }
5314
5315     rect->top = drawable_height - rect->top;
5316     rect->bottom = drawable_height - rect->bottom;
5317 }
5318
5319 static void surface_blt_to_drawable(const struct wined3d_device *device,
5320         enum wined3d_texture_filter_type filter, BOOL color_key,
5321         struct wined3d_surface *src_surface, const RECT *src_rect_in,
5322         struct wined3d_surface *dst_surface, const RECT *dst_rect_in)
5323 {
5324     const struct wined3d_gl_info *gl_info;
5325     struct wined3d_context *context;
5326     RECT src_rect, dst_rect;
5327
5328     src_rect = *src_rect_in;
5329     dst_rect = *dst_rect_in;
5330
5331     /* Make sure the surface is up-to-date. This should probably use
5332      * surface_load_location() and worry about the destination surface too,
5333      * unless we're overwriting it completely. */
5334     surface_internal_preload(src_surface, SRGB_RGB);
5335
5336     /* Activate the destination context, set it up for blitting */
5337     context = context_acquire(device, dst_surface);
5338     gl_info = context->gl_info;
5339     context_apply_blit_state(context, device);
5340
5341     if (!surface_is_offscreen(dst_surface))
5342         surface_translate_drawable_coords(dst_surface, context->win_handle, &dst_rect);
5343
5344     device->blitter->set_shader(device->blit_priv, context, src_surface);
5345
5346     ENTER_GL();
5347
5348     if (color_key)
5349     {
5350         gl_info->gl_ops.gl.p_glEnable(GL_ALPHA_TEST);
5351         checkGLcall("glEnable(GL_ALPHA_TEST)");
5352
5353         /* When the primary render target uses P8, the alpha component
5354          * contains the palette index. Which means that the colorkey is one of
5355          * the palette entries. In other cases pixels that should be masked
5356          * away have alpha set to 0. */
5357         if (primary_render_target_is_p8(device))
5358             gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL,
5359                     (float)src_surface->src_blt_color_key.color_space_low_value / 256.0f);
5360         else
5361             gl_info->gl_ops.gl.p_glAlphaFunc(GL_NOTEQUAL, 0.0f);
5362         checkGLcall("glAlphaFunc");
5363     }
5364     else
5365     {
5366         gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5367         checkGLcall("glDisable(GL_ALPHA_TEST)");
5368     }
5369
5370     draw_textured_quad(src_surface, context, &src_rect, &dst_rect, filter);
5371
5372     if (color_key)
5373     {
5374         gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5375         checkGLcall("glDisable(GL_ALPHA_TEST)");
5376     }
5377
5378     LEAVE_GL();
5379
5380     /* Leave the opengl state valid for blitting */
5381     device->blitter->unset_shader(context->gl_info);
5382
5383     if (wined3d_settings.strict_draw_ordering
5384             || (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN
5385             && (dst_surface->container.u.swapchain->front_buffer == dst_surface)))
5386         gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5387
5388     context_release(context);
5389 }
5390
5391 /* Do not call while under the GL lock. */
5392 HRESULT surface_color_fill(struct wined3d_surface *s, const RECT *rect, const struct wined3d_color *color)
5393 {
5394     struct wined3d_device *device = s->resource.device;
5395     const struct blit_shader *blitter;
5396
5397     blitter = wined3d_select_blitter(&device->adapter->gl_info, WINED3D_BLIT_OP_COLOR_FILL,
5398             NULL, 0, 0, NULL, rect, s->resource.usage, s->resource.pool, s->resource.format);
5399     if (!blitter)
5400     {
5401         FIXME("No blitter is capable of performing the requested color fill operation.\n");
5402         return WINED3DERR_INVALIDCALL;
5403     }
5404
5405     return blitter->color_fill(device, s, rect, color);
5406 }
5407
5408 /* Do not call while under the GL lock. */
5409 static HRESULT IWineD3DSurfaceImpl_BltOverride(struct wined3d_surface *dst_surface, const RECT *dst_rect,
5410         struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags, const WINEDDBLTFX *DDBltFx,
5411         enum wined3d_texture_filter_type filter)
5412 {
5413     struct wined3d_device *device = dst_surface->resource.device;
5414     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5415     struct wined3d_swapchain *srcSwapchain = NULL, *dstSwapchain = NULL;
5416
5417     TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, blt_fx %p, filter %s.\n",
5418             dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
5419             flags, DDBltFx, debug_d3dtexturefiltertype(filter));
5420
5421     /* Get the swapchain. One of the surfaces has to be a primary surface */
5422     if (dst_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5423     {
5424         WARN("Destination is in sysmem, rejecting gl blt\n");
5425         return WINED3DERR_INVALIDCALL;
5426     }
5427
5428     if (dst_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5429         dstSwapchain = dst_surface->container.u.swapchain;
5430
5431     if (src_surface)
5432     {
5433         if (src_surface->resource.pool == WINED3D_POOL_SYSTEM_MEM)
5434         {
5435             WARN("Src is in sysmem, rejecting gl blt\n");
5436             return WINED3DERR_INVALIDCALL;
5437         }
5438
5439         if (src_surface->container.type == WINED3D_CONTAINER_SWAPCHAIN)
5440             srcSwapchain = src_surface->container.u.swapchain;
5441     }
5442
5443     /* Early sort out of cases where no render target is used */
5444     if (!dstSwapchain && !srcSwapchain
5445             && src_surface != device->fb.render_targets[0]
5446             && dst_surface != device->fb.render_targets[0])
5447     {
5448         TRACE("No surface is render target, not using hardware blit.\n");
5449         return WINED3DERR_INVALIDCALL;
5450     }
5451
5452     /* No destination color keying supported */
5453     if (flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE))
5454     {
5455         /* Can we support that with glBlendFunc if blitting to the frame buffer? */
5456         TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
5457         return WINED3DERR_INVALIDCALL;
5458     }
5459
5460     if (dstSwapchain && dstSwapchain == srcSwapchain)
5461     {
5462         FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
5463         return WINED3DERR_INVALIDCALL;
5464     }
5465
5466     if (dstSwapchain && srcSwapchain)
5467     {
5468         FIXME("Implement hardware blit between two different swapchains\n");
5469         return WINED3DERR_INVALIDCALL;
5470     }
5471
5472     if (dstSwapchain)
5473     {
5474         /* Handled with regular texture -> swapchain blit */
5475         if (src_surface == device->fb.render_targets[0])
5476             TRACE("Blit from active render target to a swapchain\n");
5477     }
5478     else if (srcSwapchain && dst_surface == device->fb.render_targets[0])
5479     {
5480         FIXME("Implement blit from a swapchain to the active render target\n");
5481         return WINED3DERR_INVALIDCALL;
5482     }
5483
5484     if ((srcSwapchain || src_surface == device->fb.render_targets[0]) && !dstSwapchain)
5485     {
5486         /* Blit from render target to texture */
5487         BOOL stretchx;
5488
5489         /* P8 read back is not implemented */
5490         if (src_surface->resource.format->id == WINED3DFMT_P8_UINT
5491                 || dst_surface->resource.format->id == WINED3DFMT_P8_UINT)
5492         {
5493             TRACE("P8 read back not supported by frame buffer to texture blit\n");
5494             return WINED3DERR_INVALIDCALL;
5495         }
5496
5497         if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
5498         {
5499             TRACE("Color keying not supported by frame buffer to texture blit\n");
5500             return WINED3DERR_INVALIDCALL;
5501             /* Destination color key is checked above */
5502         }
5503
5504         if (dst_rect->right - dst_rect->left != src_rect->right - src_rect->left)
5505             stretchx = TRUE;
5506         else
5507             stretchx = FALSE;
5508
5509         /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
5510          * flip the image nor scale it.
5511          *
5512          * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
5513          * -> If the app wants a image width an unscaled width, copy it line per line
5514          * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
5515          *    than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
5516          *    back buffer. This is slower than reading line per line, thus not used for flipping
5517          * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
5518          *    pixel by pixel. */
5519         if (!stretchx || dst_rect->right - dst_rect->left > src_surface->resource.width
5520                 || dst_rect->bottom - dst_rect->top > src_surface->resource.height)
5521         {
5522             TRACE("No stretching in x direction, using direct framebuffer -> texture copy.\n");
5523             fb_copy_to_texture_direct(dst_surface, src_surface, src_rect, dst_rect, filter);
5524         }
5525         else
5526         {
5527             TRACE("Using hardware stretching to flip / stretch the texture.\n");
5528             fb_copy_to_texture_hwstretch(dst_surface, src_surface, src_rect, dst_rect, filter);
5529         }
5530
5531         if (!dst_surface->resource.map_count && !(dst_surface->flags & SFLAG_DONOTFREE))
5532         {
5533             HeapFree(GetProcessHeap(), 0, dst_surface->resource.heapMemory);
5534             dst_surface->resource.allocatedMemory = NULL;
5535             dst_surface->resource.heapMemory = NULL;
5536         }
5537         else
5538         {
5539             dst_surface->flags &= ~SFLAG_INSYSMEM;
5540         }
5541
5542         return WINED3D_OK;
5543     }
5544     else if (src_surface)
5545     {
5546         /* Blit from offscreen surface to render target */
5547         struct wined3d_color_key old_blt_key = src_surface->src_blt_color_key;
5548         DWORD oldCKeyFlags = src_surface->CKeyFlags;
5549
5550         TRACE("Blt from surface %p to rendertarget %p\n", src_surface, dst_surface);
5551
5552         if (!device->blitter->blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
5553                 src_rect, src_surface->resource.usage, src_surface->resource.pool, src_surface->resource.format,
5554                 dst_rect, dst_surface->resource.usage, dst_surface->resource.pool, dst_surface->resource.format))
5555         {
5556             FIXME("Unsupported blit operation falling back to software\n");
5557             return WINED3DERR_INVALIDCALL;
5558         }
5559
5560         /* Color keying: Check if we have to do a color keyed blt,
5561          * and if not check if a color key is activated.
5562          *
5563          * Just modify the color keying parameters in the surface and restore them afterwards
5564          * The surface keeps track of the color key last used to load the opengl surface.
5565          * PreLoad will catch the change to the flags and color key and reload if necessary.
5566          */
5567         if (flags & WINEDDBLT_KEYSRC)
5568         {
5569             /* Use color key from surface */
5570         }
5571         else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
5572         {
5573             /* Use color key from DDBltFx */
5574             src_surface->CKeyFlags |= WINEDDSD_CKSRCBLT;
5575             src_surface->src_blt_color_key = DDBltFx->ddckSrcColorkey;
5576         }
5577         else
5578         {
5579             /* Do not use color key */
5580             src_surface->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
5581         }
5582
5583         surface_blt_to_drawable(device, filter, flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE),
5584                 src_surface, src_rect, dst_surface, dst_rect);
5585
5586         /* Restore the color key parameters */
5587         src_surface->CKeyFlags = oldCKeyFlags;
5588         src_surface->src_blt_color_key = old_blt_key;
5589
5590         surface_modify_location(dst_surface, dst_surface->draw_binding, TRUE);
5591
5592         return WINED3D_OK;
5593     }
5594
5595     /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
5596     TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
5597     return WINED3DERR_INVALIDCALL;
5598 }
5599
5600 /* GL locking is done by the caller */
5601 static void surface_depth_blt(const struct wined3d_surface *surface, struct wined3d_context *context,
5602         GLuint texture, GLint x, GLint y, GLsizei w, GLsizei h, GLenum target)
5603 {
5604     struct wined3d_device *device = surface->resource.device;
5605     const struct wined3d_gl_info *gl_info = context->gl_info;
5606     GLint compare_mode = GL_NONE;
5607     struct blt_info info;
5608     GLint old_binding = 0;
5609     RECT rect;
5610
5611     gl_info->gl_ops.gl.p_glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
5612
5613     gl_info->gl_ops.gl.p_glDisable(GL_CULL_FACE);
5614     gl_info->gl_ops.gl.p_glDisable(GL_BLEND);
5615     gl_info->gl_ops.gl.p_glDisable(GL_ALPHA_TEST);
5616     gl_info->gl_ops.gl.p_glDisable(GL_SCISSOR_TEST);
5617     gl_info->gl_ops.gl.p_glDisable(GL_STENCIL_TEST);
5618     gl_info->gl_ops.gl.p_glEnable(GL_DEPTH_TEST);
5619     gl_info->gl_ops.gl.p_glDepthFunc(GL_ALWAYS);
5620     gl_info->gl_ops.gl.p_glDepthMask(GL_TRUE);
5621     gl_info->gl_ops.gl.p_glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
5622     gl_info->gl_ops.gl.p_glViewport(x, y, w, h);
5623     gl_info->gl_ops.gl.p_glDepthRange(0.0, 1.0);
5624
5625     SetRect(&rect, 0, h, w, 0);
5626     surface_get_blt_info(target, &rect, surface->pow2Width, surface->pow2Height, &info);
5627     context_active_texture(context, context->gl_info, 0);
5628     gl_info->gl_ops.gl.p_glGetIntegerv(info.binding, &old_binding);
5629     gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, texture);
5630     if (gl_info->supported[ARB_SHADOW])
5631     {
5632         gl_info->gl_ops.gl.p_glGetTexParameteriv(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, &compare_mode);
5633         if (compare_mode != GL_NONE)
5634             gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
5635     }
5636
5637     device->shader_backend->shader_select_depth_blt(device->shader_priv,
5638             gl_info, info.tex_type, &surface->ds_current_size);
5639
5640     gl_info->gl_ops.gl.p_glBegin(GL_TRIANGLE_STRIP);
5641     gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[0]);
5642     gl_info->gl_ops.gl.p_glVertex2f(-1.0f, -1.0f);
5643     gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[1]);
5644     gl_info->gl_ops.gl.p_glVertex2f(1.0f, -1.0f);
5645     gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[2]);
5646     gl_info->gl_ops.gl.p_glVertex2f(-1.0f, 1.0f);
5647     gl_info->gl_ops.gl.p_glTexCoord3fv(info.coords[3]);
5648     gl_info->gl_ops.gl.p_glVertex2f(1.0f, 1.0f);
5649     gl_info->gl_ops.gl.p_glEnd();
5650
5651     if (compare_mode != GL_NONE)
5652         gl_info->gl_ops.gl.p_glTexParameteri(info.bind_target, GL_TEXTURE_COMPARE_MODE_ARB, compare_mode);
5653     gl_info->gl_ops.gl.p_glBindTexture(info.bind_target, old_binding);
5654
5655     gl_info->gl_ops.gl.p_glPopAttrib();
5656
5657     device->shader_backend->shader_deselect_depth_blt(device->shader_priv, gl_info);
5658 }
5659
5660 void surface_modify_ds_location(struct wined3d_surface *surface,
5661         DWORD location, UINT w, UINT h)
5662 {
5663     TRACE("surface %p, new location %#x, w %u, h %u.\n", surface, location, w, h);
5664
5665     if (location & ~(SFLAG_LOCATIONS | SFLAG_DISCARDED))
5666         FIXME("Invalid location (%#x) specified.\n", location);
5667
5668     if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5669             || (!(surface->flags & SFLAG_INTEXTURE) && (location & SFLAG_INTEXTURE)))
5670     {
5671         if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5672         {
5673             TRACE("Passing to container.\n");
5674             wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5675         }
5676     }
5677
5678     surface->ds_current_size.cx = w;
5679     surface->ds_current_size.cy = h;
5680     surface->flags &= ~(SFLAG_LOCATIONS | SFLAG_DISCARDED);
5681     surface->flags |= location;
5682 }
5683
5684 /* Context activation is done by the caller. */
5685 void surface_load_ds_location(struct wined3d_surface *surface, struct wined3d_context *context, DWORD location)
5686 {
5687     const struct wined3d_gl_info *gl_info = context->gl_info;
5688     struct wined3d_device *device = surface->resource.device;
5689     GLsizei w, h;
5690
5691     TRACE("surface %p, new location %#x.\n", surface, location);
5692
5693     /* TODO: Make this work for modes other than FBO */
5694     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
5695
5696     if (!(surface->flags & location))
5697     {
5698         w = surface->ds_current_size.cx;
5699         h = surface->ds_current_size.cy;
5700         surface->ds_current_size.cx = 0;
5701         surface->ds_current_size.cy = 0;
5702     }
5703     else
5704     {
5705         w = surface->resource.width;
5706         h = surface->resource.height;
5707     }
5708
5709     if (surface->ds_current_size.cx == surface->resource.width
5710             && surface->ds_current_size.cy == surface->resource.height)
5711     {
5712         TRACE("Location (%#x) is already up to date.\n", location);
5713         return;
5714     }
5715
5716     if (surface->current_renderbuffer)
5717     {
5718         FIXME("Not supported with fixed up depth stencil.\n");
5719         return;
5720     }
5721
5722     if (surface->flags & SFLAG_DISCARDED)
5723     {
5724         TRACE("Surface was discarded, no need copy data.\n");
5725         switch (location)
5726         {
5727             case SFLAG_INTEXTURE:
5728                 surface_prepare_texture(surface, context, FALSE);
5729                 break;
5730             case SFLAG_INRB_MULTISAMPLE:
5731                 surface_prepare_rb(surface, gl_info, TRUE);
5732                 break;
5733             case SFLAG_INDRAWABLE:
5734                 /* Nothing to do */
5735                 break;
5736             default:
5737                 FIXME("Unhandled location %#x\n", location);
5738         }
5739         surface->flags &= ~SFLAG_DISCARDED;
5740         surface->flags |= location;
5741         surface->ds_current_size.cx = surface->resource.width;
5742         surface->ds_current_size.cy = surface->resource.height;
5743         return;
5744     }
5745
5746     if (!(surface->flags & SFLAG_LOCATIONS))
5747     {
5748         FIXME("No up to date depth stencil location.\n");
5749         surface->flags |= location;
5750         surface->ds_current_size.cx = surface->resource.width;
5751         surface->ds_current_size.cy = surface->resource.height;
5752         return;
5753     }
5754
5755     if (location == SFLAG_INTEXTURE)
5756     {
5757         GLint old_binding = 0;
5758         GLenum bind_target;
5759
5760         /* The render target is allowed to be smaller than the depth/stencil
5761          * buffer, so the onscreen depth/stencil buffer is potentially smaller
5762          * than the offscreen surface. Don't overwrite the offscreen surface
5763          * with undefined data. */
5764         w = min(w, context->swapchain->desc.backbuffer_width);
5765         h = min(h, context->swapchain->desc.backbuffer_height);
5766
5767         TRACE("Copying onscreen depth buffer to depth texture.\n");
5768
5769         ENTER_GL();
5770
5771         if (!device->depth_blt_texture)
5772             gl_info->gl_ops.gl.p_glGenTextures(1, &device->depth_blt_texture);
5773
5774         /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
5775          * directly on the FBO texture. That's because we need to flip. */
5776         context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5777                 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5778         if (surface->texture_target == GL_TEXTURE_RECTANGLE_ARB)
5779         {
5780             gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5781             bind_target = GL_TEXTURE_RECTANGLE_ARB;
5782         }
5783         else
5784         {
5785             gl_info->gl_ops.gl.p_glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5786             bind_target = GL_TEXTURE_2D;
5787         }
5788         gl_info->gl_ops.gl.p_glBindTexture(bind_target, device->depth_blt_texture);
5789         /* We use GL_DEPTH_COMPONENT instead of the surface's specific
5790          * internal format, because the internal format might include stencil
5791          * data. In principle we should copy stencil data as well, but unless
5792          * the driver supports stencil export it's hard to do, and doesn't
5793          * seem to be needed in practice. If the hardware doesn't support
5794          * writing stencil data, the glCopyTexImage2D() call might trigger
5795          * software fallbacks. */
5796         gl_info->gl_ops.gl.p_glCopyTexImage2D(bind_target, 0, GL_DEPTH_COMPONENT, 0, 0, w, h, 0);
5797         gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5798         gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5799         gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
5800         gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
5801         gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
5802         gl_info->gl_ops.gl.p_glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5803         gl_info->gl_ops.gl.p_glBindTexture(bind_target, old_binding);
5804
5805         context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5806                 NULL, surface, SFLAG_INTEXTURE);
5807         context_set_draw_buffer(context, GL_NONE);
5808         gl_info->gl_ops.gl.p_glReadBuffer(GL_NONE);
5809
5810         /* Do the actual blit */
5811         surface_depth_blt(surface, context, device->depth_blt_texture, 0, 0, w, h, bind_target);
5812         checkGLcall("depth_blt");
5813
5814         context_invalidate_state(context, STATE_FRAMEBUFFER);
5815
5816         LEAVE_GL();
5817
5818         if (wined3d_settings.strict_draw_ordering)
5819             gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5820     }
5821     else if (location == SFLAG_INDRAWABLE)
5822     {
5823         TRACE("Copying depth texture to onscreen depth buffer.\n");
5824
5825         ENTER_GL();
5826
5827         context_apply_fbo_state_blit(context, GL_FRAMEBUFFER,
5828                 context->swapchain->front_buffer, NULL, SFLAG_INDRAWABLE);
5829         surface_depth_blt(surface, context, surface->texture_name,
5830                 0, surface->pow2Height - h, w, h, surface->texture_target);
5831         checkGLcall("depth_blt");
5832
5833         context_invalidate_state(context, STATE_FRAMEBUFFER);
5834
5835         LEAVE_GL();
5836
5837         if (wined3d_settings.strict_draw_ordering)
5838             gl_info->gl_ops.gl.p_glFlush(); /* Flush to ensure ordering across contexts. */
5839     }
5840     else
5841     {
5842         ERR("Invalid location (%#x) specified.\n", location);
5843     }
5844
5845     surface->flags |= location;
5846     surface->ds_current_size.cx = surface->resource.width;
5847     surface->ds_current_size.cy = surface->resource.height;
5848 }
5849
5850 void surface_modify_location(struct wined3d_surface *surface, DWORD location, BOOL persistent)
5851 {
5852     const struct wined3d_gl_info *gl_info = &surface->resource.device->adapter->gl_info;
5853     struct wined3d_surface *overlay;
5854
5855     TRACE("surface %p, location %s, persistent %#x.\n",
5856             surface, debug_surflocation(location), persistent);
5857
5858     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface)
5859             && !(surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
5860             && (location & SFLAG_INDRAWABLE))
5861         ERR("Trying to invalidate the SFLAG_INDRAWABLE location of an offscreen surface.\n");
5862
5863     if (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
5864             && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
5865         location |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
5866
5867     if (persistent)
5868     {
5869         if (((surface->flags & SFLAG_INTEXTURE) && !(location & SFLAG_INTEXTURE))
5870                 || ((surface->flags & SFLAG_INSRGBTEX) && !(location & SFLAG_INSRGBTEX)))
5871         {
5872             if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5873             {
5874                 TRACE("Passing to container.\n");
5875                 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5876             }
5877         }
5878         surface->flags &= ~SFLAG_LOCATIONS;
5879         surface->flags |= location;
5880
5881         /* Redraw emulated overlays, if any */
5882         if (location & SFLAG_INDRAWABLE && !list_empty(&surface->overlays))
5883         {
5884             LIST_FOR_EACH_ENTRY(overlay, &surface->overlays, struct wined3d_surface, overlay_entry)
5885             {
5886                 surface_draw_overlay(overlay);
5887             }
5888         }
5889     }
5890     else
5891     {
5892         if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (location & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)))
5893         {
5894             if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
5895             {
5896                 TRACE("Passing to container\n");
5897                 wined3d_texture_set_dirty(surface->container.u.texture, TRUE);
5898             }
5899         }
5900         surface->flags &= ~location;
5901     }
5902
5903     if (!(surface->flags & SFLAG_LOCATIONS))
5904     {
5905         ERR("Surface %p does not have any up to date location.\n", surface);
5906     }
5907 }
5908
5909 static DWORD resource_access_from_location(DWORD location)
5910 {
5911     switch (location)
5912     {
5913         case SFLAG_INSYSMEM:
5914             return WINED3D_RESOURCE_ACCESS_CPU;
5915
5916         case SFLAG_INDRAWABLE:
5917         case SFLAG_INSRGBTEX:
5918         case SFLAG_INTEXTURE:
5919         case SFLAG_INRB_MULTISAMPLE:
5920         case SFLAG_INRB_RESOLVED:
5921             return WINED3D_RESOURCE_ACCESS_GPU;
5922
5923         default:
5924             FIXME("Unhandled location %#x.\n", location);
5925             return 0;
5926     }
5927 }
5928
5929 static void surface_load_sysmem(struct wined3d_surface *surface,
5930         const struct wined3d_gl_info *gl_info, const RECT *rect)
5931 {
5932     surface_prepare_system_memory(surface);
5933
5934     if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED))
5935         surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5936
5937     /* Download the surface to system memory. */
5938     if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
5939     {
5940         struct wined3d_device *device = surface->resource.device;
5941         struct wined3d_context *context;
5942
5943         /* TODO: Use already acquired context when possible. */
5944         context = context_acquire(device, NULL);
5945
5946         surface_bind_and_dirtify(surface, context, !(surface->flags & SFLAG_INTEXTURE));
5947         surface_download_data(surface, gl_info);
5948
5949         context_release(context);
5950
5951         return;
5952     }
5953
5954     if (surface->flags & SFLAG_INDRAWABLE)
5955     {
5956         read_from_framebuffer(surface, rect, surface->resource.allocatedMemory,
5957                 wined3d_surface_get_pitch(surface));
5958         return;
5959     }
5960
5961     FIXME("Can't load surface %p with location flags %#x into sysmem.\n",
5962             surface, surface->flags & SFLAG_LOCATIONS);
5963 }
5964
5965 static HRESULT surface_load_drawable(struct wined3d_surface *surface,
5966         const struct wined3d_gl_info *gl_info, const RECT *rect)
5967 {
5968     struct wined3d_device *device = surface->resource.device;
5969     enum wined3d_conversion_type convert;
5970     struct wined3d_format format;
5971     UINT byte_count;
5972     BYTE *mem;
5973
5974     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && surface_is_offscreen(surface))
5975     {
5976         ERR("Trying to load offscreen surface into SFLAG_INDRAWABLE.\n");
5977         return WINED3DERR_INVALIDCALL;
5978     }
5979
5980     if (wined3d_settings.rendertargetlock_mode == RTL_READTEX)
5981         surface_load_location(surface, SFLAG_INTEXTURE, NULL);
5982
5983     if (surface->flags & SFLAG_INTEXTURE)
5984     {
5985         RECT r;
5986
5987         surface_get_rect(surface, rect, &r);
5988         surface_blt_to_drawable(device, WINED3D_TEXF_POINT, FALSE, surface, &r, surface, &r);
5989
5990         return WINED3D_OK;
5991     }
5992
5993     if ((surface->flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX)
5994     {
5995         /* This needs colorspace conversion from sRGB to RGB. We take the slow
5996          * path through sysmem. */
5997         surface_load_location(surface, SFLAG_INSYSMEM, rect);
5998     }
5999
6000     d3dfmt_get_conv(surface, FALSE, FALSE, &format, &convert);
6001
6002     /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6003      * SFLAG_CONVERTED but it isn't set (yet) in all cases where it is getting
6004      * called. */
6005     if ((convert != WINED3D_CT_NONE) && (surface->flags & SFLAG_PBO))
6006     {
6007         struct wined3d_context *context;
6008
6009         TRACE("Removing the pbo attached to surface %p.\n", surface);
6010
6011         /* TODO: Use already acquired context when possible. */
6012         context = context_acquire(device, NULL);
6013
6014         surface_remove_pbo(surface, gl_info);
6015
6016         context_release(context);
6017     }
6018
6019     if ((convert != WINED3D_CT_NONE) && surface->resource.allocatedMemory)
6020     {
6021         UINT height = surface->resource.height;
6022         UINT width = surface->resource.width;
6023         UINT src_pitch, dst_pitch;
6024
6025         byte_count = format.conv_byte_count;
6026         src_pitch = wined3d_surface_get_pitch(surface);
6027
6028         /* Stick to the alignment for the converted surface too, makes it
6029          * easier to load the surface. */
6030         dst_pitch = width * byte_count;
6031         dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6032
6033         if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6034         {
6035             ERR("Out of memory (%u).\n", dst_pitch * height);
6036             return E_OUTOFMEMORY;
6037         }
6038
6039         d3dfmt_convert_surface(surface->resource.allocatedMemory, mem,
6040                 src_pitch, width, height, dst_pitch, convert, surface);
6041
6042         surface->flags |= SFLAG_CONVERTED;
6043     }
6044     else
6045     {
6046         surface->flags &= ~SFLAG_CONVERTED;
6047         mem = surface->resource.allocatedMemory;
6048         byte_count = format.byte_count;
6049     }
6050
6051     flush_to_framebuffer_drawpixels(surface, rect, format.glFormat, format.glType, byte_count, mem);
6052
6053     /* Don't delete PBO memory. */
6054     if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6055         HeapFree(GetProcessHeap(), 0, mem);
6056
6057     return WINED3D_OK;
6058 }
6059
6060 static HRESULT surface_load_texture(struct wined3d_surface *surface,
6061         const struct wined3d_gl_info *gl_info, const RECT *rect, BOOL srgb)
6062 {
6063     RECT src_rect = {0, 0, surface->resource.width, surface->resource.height};
6064     struct wined3d_device *device = surface->resource.device;
6065     enum wined3d_conversion_type convert;
6066     struct wined3d_context *context;
6067     UINT width, src_pitch, dst_pitch;
6068     struct wined3d_bo_address data;
6069     struct wined3d_format format;
6070     POINT dst_point = {0, 0};
6071     BYTE *mem;
6072
6073     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO
6074             && surface_is_offscreen(surface)
6075             && (surface->flags & SFLAG_INDRAWABLE))
6076     {
6077         surface_load_fb_texture(surface, srgb);
6078
6079         return WINED3D_OK;
6080     }
6081
6082     if (surface->flags & (SFLAG_INSRGBTEX | SFLAG_INTEXTURE)
6083             && (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB)
6084             && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6085                 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6086                 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6087     {
6088         if (srgb)
6089             surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INTEXTURE,
6090                     &src_rect, surface, SFLAG_INSRGBTEX, &src_rect);
6091         else
6092             surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, SFLAG_INSRGBTEX,
6093                     &src_rect, surface, SFLAG_INTEXTURE, &src_rect);
6094
6095         return WINED3D_OK;
6096     }
6097
6098     if (surface->flags & (SFLAG_INRB_MULTISAMPLE | SFLAG_INRB_RESOLVED)
6099             && (!srgb || (surface->resource.format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE_SRGB))
6100             && fbo_blit_supported(gl_info, WINED3D_BLIT_OP_COLOR_BLIT,
6101                 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format,
6102                 NULL, surface->resource.usage, surface->resource.pool, surface->resource.format))
6103     {
6104         DWORD src_location = surface->flags & SFLAG_INRB_RESOLVED ? SFLAG_INRB_RESOLVED : SFLAG_INRB_MULTISAMPLE;
6105         DWORD dst_location = srgb ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
6106         RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6107
6108         surface_blt_fbo(device, WINED3D_TEXF_POINT, surface, src_location,
6109                 &rect, surface, dst_location, &rect);
6110
6111         return WINED3D_OK;
6112     }
6113
6114     /* Upload from system memory */
6115
6116     d3dfmt_get_conv(surface, TRUE /* We need color keying */,
6117             TRUE /* We will use textures */, &format, &convert);
6118
6119     if (srgb)
6120     {
6121         if ((surface->flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE)
6122         {
6123             /* Performance warning... */
6124             FIXME("Downloading RGB surface %p to reload it as sRGB.\n", surface);
6125             surface_load_location(surface, SFLAG_INSYSMEM, rect);
6126         }
6127     }
6128     else
6129     {
6130         if ((surface->flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX)
6131         {
6132             /* Performance warning... */
6133             FIXME("Downloading sRGB surface %p to reload it as RGB.\n", surface);
6134             surface_load_location(surface, SFLAG_INSYSMEM, rect);
6135         }
6136     }
6137
6138     if (!(surface->flags & SFLAG_INSYSMEM))
6139     {
6140         WARN("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set.\n");
6141         /* Lets hope we get it from somewhere... */
6142         surface_load_location(surface, SFLAG_INSYSMEM, rect);
6143     }
6144
6145     /* TODO: Use already acquired context when possible. */
6146     context = context_acquire(device, NULL);
6147
6148     surface_prepare_texture(surface, context, srgb);
6149     surface_bind_and_dirtify(surface, context, srgb);
6150
6151     if (surface->CKeyFlags & WINEDDSD_CKSRCBLT)
6152     {
6153         surface->flags |= SFLAG_GLCKEY;
6154         surface->gl_color_key = surface->src_blt_color_key;
6155     }
6156     else surface->flags &= ~SFLAG_GLCKEY;
6157
6158     width = surface->resource.width;
6159     src_pitch = wined3d_surface_get_pitch(surface);
6160
6161     /* Don't use PBOs for converted surfaces. During PBO conversion we look at
6162      * SFLAG_CONVERTED but it isn't set (yet) in all cases it is getting
6163      * called. */
6164     if ((convert != WINED3D_CT_NONE || format.convert) && (surface->flags & SFLAG_PBO))
6165     {
6166         TRACE("Removing the pbo attached to surface %p.\n", surface);
6167         surface_remove_pbo(surface, gl_info);
6168     }
6169
6170     if (format.convert)
6171     {
6172         /* This code is entered for texture formats which need a fixup. */
6173         UINT height = surface->resource.height;
6174
6175         /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6176         dst_pitch = width * format.conv_byte_count;
6177         dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6178
6179         if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6180         {
6181             ERR("Out of memory (%u).\n", dst_pitch * height);
6182             context_release(context);
6183             return E_OUTOFMEMORY;
6184         }
6185         format.convert(surface->resource.allocatedMemory, mem, src_pitch, width, height);
6186         format.byte_count = format.conv_byte_count;
6187         src_pitch = dst_pitch;
6188     }
6189     else if (convert != WINED3D_CT_NONE && surface->resource.allocatedMemory)
6190     {
6191         /* This code is only entered for color keying fixups */
6192         UINT height = surface->resource.height;
6193
6194         /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
6195         dst_pitch = width * format.conv_byte_count;
6196         dst_pitch = (dst_pitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
6197
6198         if (!(mem = HeapAlloc(GetProcessHeap(), 0, dst_pitch * height)))
6199         {
6200             ERR("Out of memory (%u).\n", dst_pitch * height);
6201             context_release(context);
6202             return E_OUTOFMEMORY;
6203         }
6204         d3dfmt_convert_surface(surface->resource.allocatedMemory, mem, src_pitch,
6205                 width, height, dst_pitch, convert, surface);
6206         format.byte_count = format.conv_byte_count;
6207         src_pitch = dst_pitch;
6208     }
6209     else
6210     {
6211         mem = surface->resource.allocatedMemory;
6212     }
6213
6214     data.buffer_object = surface->pbo;
6215     data.addr = mem;
6216     surface_upload_data(surface, gl_info, &format, &src_rect, src_pitch, &dst_point, srgb, &data);
6217
6218     context_release(context);
6219
6220     /* Don't delete PBO memory. */
6221     if ((mem != surface->resource.allocatedMemory) && !(surface->flags & SFLAG_PBO))
6222         HeapFree(GetProcessHeap(), 0, mem);
6223
6224     return WINED3D_OK;
6225 }
6226
6227 static void surface_multisample_resolve(struct wined3d_surface *surface)
6228 {
6229     RECT rect = {0, 0, surface->resource.width, surface->resource.height};
6230
6231     if (!(surface->flags & SFLAG_INRB_MULTISAMPLE))
6232         ERR("Trying to resolve multisampled surface %p, but location SFLAG_INRB_MULTISAMPLE not current.\n", surface);
6233
6234     surface_blt_fbo(surface->resource.device, WINED3D_TEXF_POINT,
6235             surface, SFLAG_INRB_MULTISAMPLE, &rect, surface, SFLAG_INRB_RESOLVED, &rect);
6236 }
6237
6238 HRESULT surface_load_location(struct wined3d_surface *surface, DWORD location, const RECT *rect)
6239 {
6240     struct wined3d_device *device = surface->resource.device;
6241     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
6242     HRESULT hr;
6243
6244     TRACE("surface %p, location %s, rect %s.\n", surface, debug_surflocation(location), wine_dbgstr_rect(rect));
6245
6246     if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL)
6247     {
6248         if (location == SFLAG_INTEXTURE)
6249         {
6250             struct wined3d_context *context = context_acquire(device, NULL);
6251             surface_load_ds_location(surface, context, location);
6252             context_release(context);
6253             return WINED3D_OK;
6254         }
6255         else
6256         {
6257             FIXME("Unimplemented location %s for depth/stencil buffers.\n", debug_surflocation(location));
6258             return WINED3DERR_INVALIDCALL;
6259         }
6260     }
6261
6262     if (location == SFLAG_INSRGBTEX && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6263         location = SFLAG_INTEXTURE;
6264
6265     if (surface->flags & location)
6266     {
6267         TRACE("Location already up to date.\n");
6268
6269         if (location == SFLAG_INSYSMEM && !(surface->flags & SFLAG_PBO)
6270                 && surface_need_pbo(surface, gl_info))
6271             surface_load_pbo(surface, gl_info);
6272
6273         return WINED3D_OK;
6274     }
6275
6276     if (WARN_ON(d3d_surface))
6277     {
6278         DWORD required_access = resource_access_from_location(location);
6279         if ((surface->resource.access_flags & required_access) != required_access)
6280             WARN("Operation requires %#x access, but surface only has %#x.\n",
6281                     required_access, surface->resource.access_flags);
6282     }
6283
6284     if (!(surface->flags & SFLAG_LOCATIONS))
6285     {
6286         ERR("Surface %p does not have any up to date location.\n", surface);
6287         surface->flags |= SFLAG_LOST;
6288         return WINED3DERR_DEVICELOST;
6289     }
6290
6291     switch (location)
6292     {
6293         case SFLAG_INSYSMEM:
6294             surface_load_sysmem(surface, gl_info, rect);
6295             break;
6296
6297         case SFLAG_INDRAWABLE:
6298             if (FAILED(hr = surface_load_drawable(surface, gl_info, rect)))
6299                 return hr;
6300             break;
6301
6302         case SFLAG_INRB_RESOLVED:
6303             surface_multisample_resolve(surface);
6304             break;
6305
6306         case SFLAG_INTEXTURE:
6307         case SFLAG_INSRGBTEX:
6308             if (FAILED(hr = surface_load_texture(surface, gl_info, rect, location == SFLAG_INSRGBTEX)))
6309                 return hr;
6310             break;
6311
6312         default:
6313             ERR("Don't know how to handle location %#x.\n", location);
6314             break;
6315     }
6316
6317     if (!rect)
6318     {
6319         surface->flags |= location;
6320
6321         if (location != SFLAG_INSYSMEM && (surface->flags & SFLAG_INSYSMEM))
6322             surface_evict_sysmem(surface);
6323     }
6324
6325     if (surface->flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)
6326             && gl_info->supported[EXT_TEXTURE_SRGB_DECODE])
6327     {
6328         surface->flags |= (SFLAG_INTEXTURE | SFLAG_INSRGBTEX);
6329     }
6330
6331     return WINED3D_OK;
6332 }
6333
6334 BOOL surface_is_offscreen(const struct wined3d_surface *surface)
6335 {
6336     struct wined3d_swapchain *swapchain = surface->container.u.swapchain;
6337
6338     /* Not on a swapchain - must be offscreen */
6339     if (surface->container.type != WINED3D_CONTAINER_SWAPCHAIN) return TRUE;
6340
6341     /* The front buffer is always onscreen */
6342     if (surface == swapchain->front_buffer) return FALSE;
6343
6344     /* If the swapchain is rendered to an FBO, the backbuffer is
6345      * offscreen, otherwise onscreen */
6346     return swapchain->render_to_fbo;
6347 }
6348
6349 static HRESULT ffp_blit_alloc(struct wined3d_device *device) { return WINED3D_OK; }
6350 /* Context activation is done by the caller. */
6351 static void ffp_blit_free(struct wined3d_device *device) { }
6352
6353 /* This function is used in case of 8bit paletted textures using GL_EXT_paletted_texture */
6354 /* Context activation is done by the caller. */
6355 static void ffp_blit_p8_upload_palette(const struct wined3d_surface *surface, const struct wined3d_gl_info *gl_info)
6356 {
6357     BYTE table[256][4];
6358     BOOL colorkey_active = (surface->CKeyFlags & WINEDDSD_CKSRCBLT) != 0;
6359     GLenum target;
6360
6361     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6362         target = surface->container.u.texture->target;
6363     else
6364         target = surface->texture_target;
6365
6366     d3dfmt_p8_init_palette(surface, table, colorkey_active);
6367
6368     TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
6369     ENTER_GL();
6370     GL_EXTCALL(glColorTableEXT(target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
6371     LEAVE_GL();
6372 }
6373
6374 /* Context activation is done by the caller. */
6375 static HRESULT ffp_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6376 {
6377     enum complex_fixup fixup = get_complex_fixup(surface->resource.format->color_fixup);
6378     const struct wined3d_gl_info *gl_info = context->gl_info;
6379     GLenum target;
6380
6381     if (surface->container.type == WINED3D_CONTAINER_TEXTURE)
6382         target = surface->container.u.texture->target;
6383     else
6384         target = surface->texture_target;
6385
6386     /* When EXT_PALETTED_TEXTURE is around, palette conversion is done by the GPU
6387      * else the surface is converted in software at upload time in LoadLocation.
6388      */
6389     if (!(surface->flags & SFLAG_CONVERTED) && fixup == COMPLEX_FIXUP_P8
6390             && gl_info->supported[EXT_PALETTED_TEXTURE])
6391         ffp_blit_p8_upload_palette(surface, gl_info);
6392
6393     ENTER_GL();
6394     gl_info->gl_ops.gl.p_glEnable(target);
6395     checkGLcall("glEnable(target)");
6396     LEAVE_GL();
6397     return WINED3D_OK;
6398 }
6399
6400 /* Context activation is done by the caller. */
6401 static void ffp_blit_unset(const struct wined3d_gl_info *gl_info)
6402 {
6403     ENTER_GL();
6404     gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_2D);
6405     checkGLcall("glDisable(GL_TEXTURE_2D)");
6406     if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
6407     {
6408         gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_CUBE_MAP_ARB);
6409         checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
6410     }
6411     if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
6412     {
6413         gl_info->gl_ops.gl.p_glDisable(GL_TEXTURE_RECTANGLE_ARB);
6414         checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
6415     }
6416     LEAVE_GL();
6417 }
6418
6419 static BOOL ffp_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6420         const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6421         const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6422 {
6423     enum complex_fixup src_fixup;
6424
6425     switch (blit_op)
6426     {
6427         case WINED3D_BLIT_OP_COLOR_BLIT:
6428             if (src_pool == WINED3D_POOL_SYSTEM_MEM || dst_pool == WINED3D_POOL_SYSTEM_MEM)
6429                 return FALSE;
6430
6431             src_fixup = get_complex_fixup(src_format->color_fixup);
6432             if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
6433             {
6434                 TRACE("Checking support for fixup:\n");
6435                 dump_color_fixup_desc(src_format->color_fixup);
6436             }
6437
6438             if (!is_identity_fixup(dst_format->color_fixup))
6439             {
6440                 TRACE("Destination fixups are not supported\n");
6441                 return FALSE;
6442             }
6443
6444             if (src_fixup == COMPLEX_FIXUP_P8 && gl_info->supported[EXT_PALETTED_TEXTURE])
6445             {
6446                 TRACE("P8 fixup supported\n");
6447                 return TRUE;
6448             }
6449
6450             /* We only support identity conversions. */
6451             if (is_identity_fixup(src_format->color_fixup))
6452             {
6453                 TRACE("[OK]\n");
6454                 return TRUE;
6455             }
6456
6457             TRACE("[FAILED]\n");
6458             return FALSE;
6459
6460         case WINED3D_BLIT_OP_COLOR_FILL:
6461             if (dst_pool == WINED3D_POOL_SYSTEM_MEM)
6462                 return FALSE;
6463
6464             if (wined3d_settings.offscreen_rendering_mode == ORM_FBO)
6465             {
6466                 if (!((dst_format->flags & WINED3DFMT_FLAG_FBO_ATTACHABLE) || (dst_usage & WINED3DUSAGE_RENDERTARGET)))
6467                     return FALSE;
6468             }
6469             else if (!(dst_usage & WINED3DUSAGE_RENDERTARGET))
6470             {
6471                 TRACE("Color fill not supported\n");
6472                 return FALSE;
6473             }
6474
6475             /* FIXME: We should reject color fills on formats with fixups,
6476              * but this would break P8 color fills for example. */
6477
6478             return TRUE;
6479
6480         case WINED3D_BLIT_OP_DEPTH_FILL:
6481             return TRUE;
6482
6483         default:
6484             TRACE("Unsupported blit_op=%d\n", blit_op);
6485             return FALSE;
6486     }
6487 }
6488
6489 /* Do not call while under the GL lock. */
6490 static HRESULT ffp_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
6491         const RECT *dst_rect, const struct wined3d_color *color)
6492 {
6493     const RECT draw_rect = {0, 0, dst_surface->resource.width, dst_surface->resource.height};
6494     struct wined3d_fb_state fb = {&dst_surface, NULL};
6495
6496     device_clear_render_targets(device, 1, &fb, 1, dst_rect, &draw_rect, WINED3DCLEAR_TARGET, color, 0.0f, 0);
6497
6498     return WINED3D_OK;
6499 }
6500
6501 /* Do not call while under the GL lock. */
6502 static HRESULT ffp_blit_depth_fill(struct wined3d_device *device,
6503         struct wined3d_surface *surface, const RECT *rect, float depth)
6504 {
6505     const RECT draw_rect = {0, 0, surface->resource.width, surface->resource.height};
6506     struct wined3d_fb_state fb = {NULL, surface};
6507
6508     device_clear_render_targets(device, 0, &fb, 1, rect, &draw_rect, WINED3DCLEAR_ZBUFFER, 0, depth, 0);
6509
6510     return WINED3D_OK;
6511 }
6512
6513 const struct blit_shader ffp_blit =  {
6514     ffp_blit_alloc,
6515     ffp_blit_free,
6516     ffp_blit_set,
6517     ffp_blit_unset,
6518     ffp_blit_supported,
6519     ffp_blit_color_fill,
6520     ffp_blit_depth_fill,
6521 };
6522
6523 static HRESULT cpu_blit_alloc(struct wined3d_device *device)
6524 {
6525     return WINED3D_OK;
6526 }
6527
6528 /* Context activation is done by the caller. */
6529 static void cpu_blit_free(struct wined3d_device *device)
6530 {
6531 }
6532
6533 /* Context activation is done by the caller. */
6534 static HRESULT cpu_blit_set(void *blit_priv, struct wined3d_context *context, const struct wined3d_surface *surface)
6535 {
6536     return WINED3D_OK;
6537 }
6538
6539 /* Context activation is done by the caller. */
6540 static void cpu_blit_unset(const struct wined3d_gl_info *gl_info)
6541 {
6542 }
6543
6544 static BOOL cpu_blit_supported(const struct wined3d_gl_info *gl_info, enum wined3d_blit_op blit_op,
6545         const RECT *src_rect, DWORD src_usage, enum wined3d_pool src_pool, const struct wined3d_format *src_format,
6546         const RECT *dst_rect, DWORD dst_usage, enum wined3d_pool dst_pool, const struct wined3d_format *dst_format)
6547 {
6548     if (blit_op == WINED3D_BLIT_OP_COLOR_FILL)
6549     {
6550         return TRUE;
6551     }
6552
6553     return FALSE;
6554 }
6555
6556 static HRESULT surface_cpu_blt_compressed(const BYTE *src_data, BYTE *dst_data,
6557         UINT src_pitch, UINT dst_pitch, UINT update_w, UINT update_h,
6558         const struct wined3d_format *format, DWORD flags, const WINEDDBLTFX *fx)
6559 {
6560     UINT row_block_count;
6561     const BYTE *src_row;
6562     BYTE *dst_row;
6563     UINT x, y;
6564
6565     src_row = src_data;
6566     dst_row = dst_data;
6567
6568     row_block_count = (update_w + format->block_width - 1) / format->block_width;
6569
6570     if (!flags)
6571     {
6572         for (y = 0; y < update_h; y += format->block_height)
6573         {
6574             memcpy(dst_row, src_row, row_block_count * format->block_byte_count);
6575             src_row += src_pitch;
6576             dst_row += dst_pitch;
6577         }
6578
6579         return WINED3D_OK;
6580     }
6581
6582     if (flags == WINEDDBLT_DDFX && fx->dwDDFX == WINEDDBLTFX_MIRRORUPDOWN)
6583     {
6584         src_row += (((update_h / format->block_height) - 1) * src_pitch);
6585
6586         switch (format->id)
6587         {
6588             case WINED3DFMT_DXT1:
6589                 for (y = 0; y < update_h; y += format->block_height)
6590                 {
6591                     struct block
6592                     {
6593                         WORD color[2];
6594                         BYTE control_row[4];
6595                     };
6596
6597                     const struct block *s = (const struct block *)src_row;
6598                     struct block *d = (struct block *)dst_row;
6599
6600                     for (x = 0; x < row_block_count; ++x)
6601                     {
6602                         d[x].color[0] = s[x].color[0];
6603                         d[x].color[1] = s[x].color[1];
6604                         d[x].control_row[0] = s[x].control_row[3];
6605                         d[x].control_row[1] = s[x].control_row[2];
6606                         d[x].control_row[2] = s[x].control_row[1];
6607                         d[x].control_row[3] = s[x].control_row[0];
6608                     }
6609                     src_row -= src_pitch;
6610                     dst_row += dst_pitch;
6611                 }
6612                 return WINED3D_OK;
6613
6614             case WINED3DFMT_DXT3:
6615                 for (y = 0; y < update_h; y += format->block_height)
6616                 {
6617                     struct block
6618                     {
6619                         WORD alpha_row[4];
6620                         WORD color[2];
6621                         BYTE control_row[4];
6622                     };
6623
6624                     const struct block *s = (const struct block *)src_row;
6625                     struct block *d = (struct block *)dst_row;
6626
6627                     for (x = 0; x < row_block_count; ++x)
6628                     {
6629                         d[x].alpha_row[0] = s[x].alpha_row[3];
6630                         d[x].alpha_row[1] = s[x].alpha_row[2];
6631                         d[x].alpha_row[2] = s[x].alpha_row[1];
6632                         d[x].alpha_row[3] = s[x].alpha_row[0];
6633                         d[x].color[0] = s[x].color[0];
6634                         d[x].color[1] = s[x].color[1];
6635                         d[x].control_row[0] = s[x].control_row[3];
6636                         d[x].control_row[1] = s[x].control_row[2];
6637                         d[x].control_row[2] = s[x].control_row[1];
6638                         d[x].control_row[3] = s[x].control_row[0];
6639                     }
6640                     src_row -= src_pitch;
6641                     dst_row += dst_pitch;
6642                 }
6643                 return WINED3D_OK;
6644
6645             default:
6646                 FIXME("Compressed flip not implemented for format %s.\n",
6647                         debug_d3dformat(format->id));
6648                 return E_NOTIMPL;
6649         }
6650     }
6651
6652     FIXME("Unsupported blit on compressed surface (format %s, flags %#x, DDFX %#x).\n",
6653             debug_d3dformat(format->id), flags, flags & WINEDDBLT_DDFX ? fx->dwDDFX : 0);
6654
6655     return E_NOTIMPL;
6656 }
6657
6658 static HRESULT surface_cpu_blt(struct wined3d_surface *dst_surface, const RECT *dst_rect,
6659         struct wined3d_surface *src_surface, const RECT *src_rect, DWORD flags,
6660         const WINEDDBLTFX *fx, enum wined3d_texture_filter_type filter)
6661 {
6662     int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
6663     const struct wined3d_format *src_format, *dst_format;
6664     struct wined3d_surface *orig_src = src_surface;
6665     struct wined3d_map_desc dst_map, src_map;
6666     const BYTE *sbase = NULL;
6667     HRESULT hr = WINED3D_OK;
6668     const BYTE *sbuf;
6669     BYTE *dbuf;
6670     int x, y;
6671
6672     TRACE("dst_surface %p, dst_rect %s, src_surface %p, src_rect %s, flags %#x, fx %p, filter %s.\n",
6673             dst_surface, wine_dbgstr_rect(dst_rect), src_surface, wine_dbgstr_rect(src_rect),
6674             flags, fx, debug_d3dtexturefiltertype(filter));
6675
6676     if (src_surface == dst_surface)
6677     {
6678         wined3d_surface_map(dst_surface, &dst_map, NULL, 0);
6679         src_map = dst_map;
6680         src_format = dst_surface->resource.format;
6681         dst_format = src_format;
6682     }
6683     else
6684     {
6685         dst_format = dst_surface->resource.format;
6686         if (src_surface)
6687         {
6688             if (dst_surface->resource.format->id != src_surface->resource.format->id)
6689             {
6690                 src_surface = surface_convert_format(src_surface, dst_format->id);
6691                 if (!src_surface)
6692                 {
6693                     /* The conv function writes a FIXME */
6694                     WARN("Cannot convert source surface format to dest format.\n");
6695                     goto release;
6696                 }
6697             }
6698             wined3d_surface_map(src_surface, &src_map, NULL, WINED3D_MAP_READONLY);
6699             src_format = src_surface->resource.format;
6700         }
6701         else
6702         {
6703             src_format = dst_format;
6704         }
6705
6706         wined3d_surface_map(dst_surface, &dst_map, dst_rect, 0);
6707     }
6708
6709     bpp = dst_surface->resource.format->byte_count;
6710     srcheight = src_rect->bottom - src_rect->top;
6711     srcwidth = src_rect->right - src_rect->left;
6712     dstheight = dst_rect->bottom - dst_rect->top;
6713     dstwidth = dst_rect->right - dst_rect->left;
6714     width = (dst_rect->right - dst_rect->left) * bpp;
6715
6716     if (src_surface)
6717         sbase = (BYTE *)src_map.data
6718                 + ((src_rect->top / src_format->block_height) * src_map.row_pitch)
6719                 + ((src_rect->left / src_format->block_width) * src_format->block_byte_count);
6720     if (src_surface != dst_surface)
6721         dbuf = dst_map.data;
6722     else
6723         dbuf = (BYTE *)dst_map.data
6724                 + ((dst_rect->top / dst_format->block_height) * dst_map.row_pitch)
6725                 + ((dst_rect->left / dst_format->block_width) * dst_format->block_byte_count);
6726
6727     if (src_format->flags & dst_format->flags & WINED3DFMT_FLAG_BLOCKS)
6728     {
6729         TRACE("%s -> %s copy.\n", debug_d3dformat(src_format->id), debug_d3dformat(dst_format->id));
6730
6731         if (src_surface == dst_surface)
6732         {
6733             FIXME("Only plain blits supported on compressed surfaces.\n");
6734             hr = E_NOTIMPL;
6735             goto release;
6736         }
6737
6738         if (srcheight != dstheight || srcwidth != dstwidth)
6739         {
6740             WARN("Stretching not supported on compressed surfaces.\n");
6741             hr = WINED3DERR_INVALIDCALL;
6742             goto release;
6743         }
6744
6745         if (!surface_check_block_align(src_surface, src_rect))
6746         {
6747             WARN("Source rectangle not block-aligned.\n");
6748             hr = WINED3DERR_INVALIDCALL;
6749             goto release;
6750         }
6751
6752         if (!surface_check_block_align(dst_surface, dst_rect))
6753         {
6754             WARN("Destination rectangle not block-aligned.\n");
6755             hr = WINED3DERR_INVALIDCALL;
6756             goto release;
6757         }
6758
6759         hr = surface_cpu_blt_compressed(sbase, dbuf,
6760                 src_map.row_pitch, dst_map.row_pitch, dstwidth, dstheight,
6761                 src_format, flags, fx);
6762         goto release;
6763     }
6764
6765     /* First, all the 'source-less' blits */
6766     if (flags & WINEDDBLT_COLORFILL)
6767     {
6768         hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, fx->u5.dwFillColor);
6769         flags &= ~WINEDDBLT_COLORFILL;
6770     }
6771
6772     if (flags & WINEDDBLT_DEPTHFILL)
6773     {
6774         FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
6775     }
6776     if (flags & WINEDDBLT_ROP)
6777     {
6778         /* Catch some degenerate cases here. */
6779         switch (fx->dwROP)
6780         {
6781             case BLACKNESS:
6782                 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, 0);
6783                 break;
6784             case 0xaa0029: /* No-op */
6785                 break;
6786             case WHITENESS:
6787                 hr = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp, dst_map.row_pitch, ~0U);
6788                 break;
6789             case SRCCOPY: /* Well, we do that below? */
6790                 break;
6791             default:
6792                 FIXME("Unsupported raster op: %08x Pattern: %p\n", fx->dwROP, fx->u5.lpDDSPattern);
6793                 goto error;
6794         }
6795         flags &= ~WINEDDBLT_ROP;
6796     }
6797     if (flags & WINEDDBLT_DDROPS)
6798     {
6799         FIXME("\tDdraw Raster Ops: %08x Pattern: %p\n", fx->dwDDROP, fx->u5.lpDDSPattern);
6800     }
6801     /* Now the 'with source' blits. */
6802     if (src_surface)
6803     {
6804         int sx, xinc, sy, yinc;
6805
6806         if (!dstwidth || !dstheight) /* Hmm... stupid program? */
6807             goto release;
6808
6809         if (filter != WINED3D_TEXF_NONE && filter != WINED3D_TEXF_POINT
6810                 && (srcwidth != dstwidth || srcheight != dstheight))
6811         {
6812             /* Can happen when d3d9 apps do a StretchRect() call which isn't handled in GL. */
6813             FIXME("Filter %s not supported in software blit.\n", debug_d3dtexturefiltertype(filter));
6814         }
6815
6816         xinc = (srcwidth << 16) / dstwidth;
6817         yinc = (srcheight << 16) / dstheight;
6818
6819         if (!flags)
6820         {
6821             /* No effects, we can cheat here. */
6822             if (dstwidth == srcwidth)
6823             {
6824                 if (dstheight == srcheight)
6825                 {
6826                     /* No stretching in either direction. This needs to be as
6827                      * fast as possible. */
6828                     sbuf = sbase;
6829
6830                     /* Check for overlapping surfaces. */
6831                     if (src_surface != dst_surface || dst_rect->top < src_rect->top
6832                             || dst_rect->right <= src_rect->left || src_rect->right <= dst_rect->left)
6833                     {
6834                         /* No overlap, or dst above src, so copy from top downwards. */
6835                         for (y = 0; y < dstheight; ++y)
6836                         {
6837                             memcpy(dbuf, sbuf, width);
6838                             sbuf += src_map.row_pitch;
6839                             dbuf += dst_map.row_pitch;
6840                         }
6841                     }
6842                     else if (dst_rect->top > src_rect->top)
6843                     {
6844                         /* Copy from bottom upwards. */
6845                         sbuf += src_map.row_pitch * dstheight;
6846                         dbuf += dst_map.row_pitch * dstheight;
6847                         for (y = 0; y < dstheight; ++y)
6848                         {
6849                             sbuf -= src_map.row_pitch;
6850                             dbuf -= dst_map.row_pitch;
6851                             memcpy(dbuf, sbuf, width);
6852                         }
6853                     }
6854                     else
6855                     {
6856                         /* Src and dst overlapping on the same line, use memmove. */
6857                         for (y = 0; y < dstheight; ++y)
6858                         {
6859                             memmove(dbuf, sbuf, width);
6860                             sbuf += src_map.row_pitch;
6861                             dbuf += dst_map.row_pitch;
6862                         }
6863                     }
6864                 }
6865                 else
6866                 {
6867                     /* Stretching in y direction only. */
6868                     for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6869                     {
6870                         sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6871                         memcpy(dbuf, sbuf, width);
6872                         dbuf += dst_map.row_pitch;
6873                     }
6874                 }
6875             }
6876             else
6877             {
6878                 /* Stretching in X direction. */
6879                 int last_sy = -1;
6880                 for (y = sy = 0; y < dstheight; ++y, sy += yinc)
6881                 {
6882                     sbuf = sbase + (sy >> 16) * src_map.row_pitch;
6883
6884                     if ((sy >> 16) == (last_sy >> 16))
6885                     {
6886                         /* This source row is the same as last source row -
6887                          * Copy the already stretched row. */
6888                         memcpy(dbuf, dbuf - dst_map.row_pitch, width);
6889                     }
6890                     else
6891                     {
6892 #define STRETCH_ROW(type) \
6893 do { \
6894     const type *s = (const type *)sbuf; \
6895     type *d = (type *)dbuf; \
6896     for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
6897         d[x] = s[sx >> 16]; \
6898 } while(0)
6899
6900                         switch(bpp)
6901                         {
6902                             case 1:
6903                                 STRETCH_ROW(BYTE);
6904                                 break;
6905                             case 2:
6906                                 STRETCH_ROW(WORD);
6907                                 break;
6908                             case 4:
6909                                 STRETCH_ROW(DWORD);
6910                                 break;
6911                             case 3:
6912                             {
6913                                 const BYTE *s;
6914                                 BYTE *d = dbuf;
6915                                 for (x = sx = 0; x < dstwidth; x++, sx+= xinc)
6916                                 {
6917                                     DWORD pixel;
6918
6919                                     s = sbuf + 3 * (sx >> 16);
6920                                     pixel = s[0] | (s[1] << 8) | (s[2] << 16);
6921                                     d[0] = (pixel      ) & 0xff;
6922                                     d[1] = (pixel >>  8) & 0xff;
6923                                     d[2] = (pixel >> 16) & 0xff;
6924                                     d += 3;
6925                                 }
6926                                 break;
6927                             }
6928                             default:
6929                                 FIXME("Stretched blit not implemented for bpp %u!\n", bpp * 8);
6930                                 hr = WINED3DERR_NOTAVAILABLE;
6931                                 goto error;
6932                         }
6933 #undef STRETCH_ROW
6934                     }
6935                     dbuf += dst_map.row_pitch;
6936                     last_sy = sy;
6937                 }
6938             }
6939         }
6940         else
6941         {
6942             LONG dstyinc = dst_map.row_pitch, dstxinc = bpp;
6943             DWORD keylow = 0xffffffff, keyhigh = 0, keymask = 0xffffffff;
6944             DWORD destkeylow = 0x0, destkeyhigh = 0xffffffff, destkeymask = 0xffffffff;
6945             if (flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE))
6946             {
6947                 /* The color keying flags are checked for correctness in ddraw */
6948                 if (flags & WINEDDBLT_KEYSRC)
6949                 {
6950                     keylow  = src_surface->src_blt_color_key.color_space_low_value;
6951                     keyhigh = src_surface->src_blt_color_key.color_space_high_value;
6952                 }
6953                 else if (flags & WINEDDBLT_KEYSRCOVERRIDE)
6954                 {
6955                     keylow = fx->ddckSrcColorkey.color_space_low_value;
6956                     keyhigh = fx->ddckSrcColorkey.color_space_high_value;
6957                 }
6958
6959                 if (flags & WINEDDBLT_KEYDEST)
6960                 {
6961                     /* Destination color keys are taken from the source surface! */
6962                     destkeylow = src_surface->dst_blt_color_key.color_space_low_value;
6963                     destkeyhigh = src_surface->dst_blt_color_key.color_space_high_value;
6964                 }
6965                 else if (flags & WINEDDBLT_KEYDESTOVERRIDE)
6966                 {
6967                     destkeylow = fx->ddckDestColorkey.color_space_low_value;
6968                     destkeyhigh = fx->ddckDestColorkey.color_space_high_value;
6969                 }
6970
6971                 if (bpp == 1)
6972                 {
6973                     keymask = 0xff;
6974                 }
6975                 else
6976                 {
6977                     DWORD masks[3];
6978                     get_color_masks(src_format, masks);
6979                     keymask = masks[0]
6980                             | masks[1]
6981                             | masks[2];
6982                 }
6983                 flags &= ~(WINEDDBLT_KEYSRC | WINEDDBLT_KEYDEST | WINEDDBLT_KEYSRCOVERRIDE | WINEDDBLT_KEYDESTOVERRIDE);
6984             }
6985
6986             if (flags & WINEDDBLT_DDFX)
6987             {
6988                 BYTE *dTopLeft, *dTopRight, *dBottomLeft, *dBottomRight, *tmp;
6989                 LONG tmpxy;
6990                 dTopLeft     = dbuf;
6991                 dTopRight    = dbuf + ((dstwidth - 1) * bpp);
6992                 dBottomLeft  = dTopLeft + ((dstheight - 1) * dst_map.row_pitch);
6993                 dBottomRight = dBottomLeft + ((dstwidth - 1) * bpp);
6994
6995                 if (fx->dwDDFX & WINEDDBLTFX_ARITHSTRETCHY)
6996                 {
6997                     /* I don't think we need to do anything about this flag */
6998                     WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_ARITHSTRETCHY\n");
6999                 }
7000                 if (fx->dwDDFX & WINEDDBLTFX_MIRRORLEFTRIGHT)
7001                 {
7002                     tmp          = dTopRight;
7003                     dTopRight    = dTopLeft;
7004                     dTopLeft     = tmp;
7005                     tmp          = dBottomRight;
7006                     dBottomRight = dBottomLeft;
7007                     dBottomLeft  = tmp;
7008                     dstxinc = dstxinc * -1;
7009                 }
7010                 if (fx->dwDDFX & WINEDDBLTFX_MIRRORUPDOWN)
7011                 {
7012                     tmp          = dTopLeft;
7013                     dTopLeft     = dBottomLeft;
7014                     dBottomLeft  = tmp;
7015                     tmp          = dTopRight;
7016                     dTopRight    = dBottomRight;
7017                     dBottomRight = tmp;
7018                     dstyinc = dstyinc * -1;
7019                 }
7020                 if (fx->dwDDFX & WINEDDBLTFX_NOTEARING)
7021                 {
7022                     /* I don't think we need to do anything about this flag */
7023                     WARN("flags=DDBLT_DDFX nothing done for WINEDDBLTFX_NOTEARING\n");
7024                 }
7025                 if (fx->dwDDFX & WINEDDBLTFX_ROTATE180)
7026                 {
7027                     tmp          = dBottomRight;
7028                     dBottomRight = dTopLeft;
7029                     dTopLeft     = tmp;
7030                     tmp          = dBottomLeft;
7031                     dBottomLeft  = dTopRight;
7032                     dTopRight    = tmp;
7033                     dstxinc = dstxinc * -1;
7034                     dstyinc = dstyinc * -1;
7035                 }
7036                 if (fx->dwDDFX & WINEDDBLTFX_ROTATE270)
7037                 {
7038                     tmp          = dTopLeft;
7039                     dTopLeft     = dBottomLeft;
7040                     dBottomLeft  = dBottomRight;
7041                     dBottomRight = dTopRight;
7042                     dTopRight    = tmp;
7043                     tmpxy   = dstxinc;
7044                     dstxinc = dstyinc;
7045                     dstyinc = tmpxy;
7046                     dstxinc = dstxinc * -1;
7047                 }
7048                 if (fx->dwDDFX & WINEDDBLTFX_ROTATE90)
7049                 {
7050                     tmp          = dTopLeft;
7051                     dTopLeft     = dTopRight;
7052                     dTopRight    = dBottomRight;
7053                     dBottomRight = dBottomLeft;
7054                     dBottomLeft  = tmp;
7055                     tmpxy   = dstxinc;
7056                     dstxinc = dstyinc;
7057                     dstyinc = tmpxy;
7058                     dstyinc = dstyinc * -1;
7059                 }
7060                 if (fx->dwDDFX & WINEDDBLTFX_ZBUFFERBASEDEST)
7061                 {
7062                     /* I don't think we need to do anything about this flag */
7063                     WARN("flags=WINEDDBLT_DDFX nothing done for WINEDDBLTFX_ZBUFFERBASEDEST\n");
7064                 }
7065                 dbuf = dTopLeft;
7066                 flags &= ~(WINEDDBLT_DDFX);
7067             }
7068
7069 #define COPY_COLORKEY_FX(type) \
7070 do { \
7071     const type *s; \
7072     type *d = (type *)dbuf, *dx, tmp; \
7073     for (y = sy = 0; y < dstheight; ++y, sy += yinc) \
7074     { \
7075         s = (const type *)(sbase + (sy >> 16) * src_map.row_pitch); \
7076         dx = d; \
7077         for (x = sx = 0; x < dstwidth; ++x, sx += xinc) \
7078         { \
7079             tmp = s[sx >> 16]; \
7080             if (((tmp & keymask) < keylow || (tmp & keymask) > keyhigh) \
7081                     && ((dx[0] & destkeymask) >= destkeylow && (dx[0] & destkeymask) <= destkeyhigh)) \
7082             { \
7083                 dx[0] = tmp; \
7084             } \
7085             dx = (type *)(((BYTE *)dx) + dstxinc); \
7086         } \
7087         d = (type *)(((BYTE *)d) + dstyinc); \
7088     } \
7089 } while(0)
7090
7091             switch (bpp)
7092             {
7093                 case 1:
7094                     COPY_COLORKEY_FX(BYTE);
7095                     break;
7096                 case 2:
7097                     COPY_COLORKEY_FX(WORD);
7098                     break;
7099                 case 4:
7100                     COPY_COLORKEY_FX(DWORD);
7101                     break;
7102                 case 3:
7103                 {
7104                     const BYTE *s;
7105                     BYTE *d = dbuf, *dx;
7106                     for (y = sy = 0; y < dstheight; ++y, sy += yinc)
7107                     {
7108                         sbuf = sbase + (sy >> 16) * src_map.row_pitch;
7109                         dx = d;
7110                         for (x = sx = 0; x < dstwidth; ++x, sx+= xinc)
7111                         {
7112                             DWORD pixel, dpixel = 0;
7113                             s = sbuf + 3 * (sx>>16);
7114                             pixel = s[0] | (s[1] << 8) | (s[2] << 16);
7115                             dpixel = dx[0] | (dx[1] << 8 ) | (dx[2] << 16);
7116                             if (((pixel & keymask) < keylow || (pixel & keymask) > keyhigh)
7117                                     && ((dpixel & keymask) >= destkeylow || (dpixel & keymask) <= keyhigh))
7118                             {
7119                                 dx[0] = (pixel      ) & 0xff;
7120                                 dx[1] = (pixel >>  8) & 0xff;
7121                                 dx[2] = (pixel >> 16) & 0xff;
7122                             }
7123                             dx += dstxinc;
7124                         }
7125                         d += dstyinc;
7126                     }
7127                     break;
7128                 }
7129                 default:
7130                     FIXME("%s color-keyed blit not implemented for bpp %u!\n",
7131                           (flags & WINEDDBLT_KEYSRC) ? "Source" : "Destination", bpp * 8);
7132                     hr = WINED3DERR_NOTAVAILABLE;
7133                     goto error;
7134 #undef COPY_COLORKEY_FX
7135             }
7136         }
7137     }
7138
7139 error:
7140     if (flags && FIXME_ON(d3d_surface))
7141     {
7142         FIXME("\tUnsupported flags: %#x.\n", flags);
7143     }
7144
7145 release:
7146     wined3d_surface_unmap(dst_surface);
7147     if (src_surface && src_surface != dst_surface)
7148         wined3d_surface_unmap(src_surface);
7149     /* Release the converted surface, if any. */
7150     if (src_surface && src_surface != orig_src)
7151         wined3d_surface_decref(src_surface);
7152
7153     return hr;
7154 }
7155
7156 /* Do not call while under the GL lock. */
7157 static HRESULT cpu_blit_color_fill(struct wined3d_device *device, struct wined3d_surface *dst_surface,
7158         const RECT *dst_rect, const struct wined3d_color *color)
7159 {
7160     static const RECT src_rect;
7161     WINEDDBLTFX BltFx;
7162
7163     memset(&BltFx, 0, sizeof(BltFx));
7164     BltFx.dwSize = sizeof(BltFx);
7165     BltFx.u5.dwFillColor = wined3d_format_convert_from_float(dst_surface, color);
7166     return surface_cpu_blt(dst_surface, dst_rect, NULL, &src_rect,
7167             WINEDDBLT_COLORFILL, &BltFx, WINED3D_TEXF_POINT);
7168 }
7169
7170 /* Do not call while under the GL lock. */
7171 static HRESULT cpu_blit_depth_fill(struct wined3d_device *device,
7172         struct wined3d_surface *surface, const RECT *rect, float depth)
7173 {
7174     FIXME("Depth filling not implemented by cpu_blit.\n");
7175     return WINED3DERR_INVALIDCALL;
7176 }
7177
7178 const struct blit_shader cpu_blit =  {
7179     cpu_blit_alloc,
7180     cpu_blit_free,
7181     cpu_blit_set,
7182     cpu_blit_unset,
7183     cpu_blit_supported,
7184     cpu_blit_color_fill,
7185     cpu_blit_depth_fill,
7186 };
7187
7188 static HRESULT surface_init(struct wined3d_surface *surface, enum wined3d_surface_type surface_type,
7189         UINT alignment, UINT width, UINT height, enum wined3d_multisample_type multisample_type,
7190         UINT multisample_quality, struct wined3d_device *device, DWORD usage, enum wined3d_format_id format_id,
7191         enum wined3d_pool pool, DWORD flags, void *parent, const struct wined3d_parent_ops *parent_ops)
7192 {
7193     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
7194     const struct wined3d_format *format = wined3d_get_format(gl_info, format_id);
7195     BOOL lockable = flags & WINED3D_SURFACE_MAPPABLE;
7196     unsigned int resource_size;
7197     HRESULT hr;
7198
7199     if (multisample_quality > 0)
7200     {
7201         FIXME("multisample_quality set to %u, substituting 0.\n", multisample_quality);
7202         multisample_quality = 0;
7203     }
7204
7205     /* Quick lockable sanity check.
7206      * TODO: remove this after surfaces, usage and lockability have been debugged properly
7207      * this function is too deep to need to care about things like this.
7208      * Levels need to be checked too, since they all affect what can be done. */
7209     switch (pool)
7210     {
7211         case WINED3D_POOL_SCRATCH:
7212             if (!lockable)
7213             {
7214                 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
7215                         "which are mutually exclusive, setting lockable to TRUE.\n");
7216                 lockable = TRUE;
7217             }
7218             break;
7219
7220         case WINED3D_POOL_SYSTEM_MEM:
7221             if (!lockable)
7222                 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
7223             break;
7224
7225         case WINED3D_POOL_MANAGED:
7226             if (usage & WINED3DUSAGE_DYNAMIC)
7227                 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
7228             break;
7229
7230         case WINED3D_POOL_DEFAULT:
7231             if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
7232                 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
7233             break;
7234
7235         default:
7236             FIXME("Unknown pool %#x.\n", pool);
7237             break;
7238     };
7239
7240     if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3D_POOL_DEFAULT)
7241         FIXME("Trying to create a render target that isn't in the default pool.\n");
7242
7243     /* FIXME: Check that the format is supported by the device. */
7244
7245     resource_size = wined3d_format_calculate_size(format, alignment, width, height);
7246     if (!resource_size)
7247         return WINED3DERR_INVALIDCALL;
7248
7249     surface->surface_type = surface_type;
7250
7251     switch (surface_type)
7252     {
7253         case WINED3D_SURFACE_TYPE_OPENGL:
7254             surface->surface_ops = &surface_ops;
7255             break;
7256
7257         case WINED3D_SURFACE_TYPE_GDI:
7258             surface->surface_ops = &gdi_surface_ops;
7259             break;
7260
7261         default:
7262             ERR("Requested unknown surface implementation %#x.\n", surface_type);
7263             return WINED3DERR_INVALIDCALL;
7264     }
7265
7266     hr = resource_init(&surface->resource, device, WINED3D_RTYPE_SURFACE, format,
7267             multisample_type, multisample_quality, usage, pool, width, height, 1,
7268             resource_size, parent, parent_ops, &surface_resource_ops);
7269     if (FAILED(hr))
7270     {
7271         WARN("Failed to initialize resource, returning %#x.\n", hr);
7272         return hr;
7273     }
7274
7275     /* "Standalone" surface. */
7276     surface_set_container(surface, WINED3D_CONTAINER_NONE, NULL);
7277
7278     list_init(&surface->overlays);
7279
7280     /* Flags */
7281     surface->flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
7282     if (flags & WINED3D_SURFACE_DISCARD)
7283         surface->flags |= SFLAG_DISCARD;
7284     if (flags & WINED3D_SURFACE_PIN_SYSMEM)
7285         surface->flags |= SFLAG_PIN_SYSMEM;
7286     if (lockable || format_id == WINED3DFMT_D16_LOCKABLE)
7287         surface->flags |= SFLAG_LOCKABLE;
7288     /* I'm not sure if this qualifies as a hack or as an optimization. It
7289      * seems reasonable to assume that lockable render targets will get
7290      * locked, so we might as well set SFLAG_DYNLOCK right at surface
7291      * creation. However, the other reason we want to do this is that several
7292      * ddraw applications access surface memory while the surface isn't
7293      * mapped. The SFLAG_DYNLOCK behaviour of keeping SYSMEM around for
7294      * future locks prevents these from crashing. */
7295     if (lockable && (usage & WINED3DUSAGE_RENDERTARGET))
7296         surface->flags |= SFLAG_DYNLOCK;
7297
7298     /* Mark the texture as dirty so that it gets loaded first time around. */
7299     surface_add_dirty_rect(surface, NULL);
7300     list_init(&surface->renderbuffers);
7301
7302     TRACE("surface %p, memory %p, size %u\n",
7303             surface, surface->resource.allocatedMemory, surface->resource.size);
7304
7305     /* Call the private setup routine */
7306     hr = surface->surface_ops->surface_private_setup(surface);
7307     if (FAILED(hr))
7308     {
7309         ERR("Private setup failed, returning %#x\n", hr);
7310         surface_cleanup(surface);
7311         return hr;
7312     }
7313
7314     /* Similar to lockable rendertargets above, creating the DIB section
7315      * during surface initialization prevents the sysmem pointer from changing
7316      * after a wined3d_surface_getdc() call. */
7317     if ((usage & WINED3DUSAGE_OWNDC) && !surface->hDC
7318             && SUCCEEDED(surface_create_dib_section(surface)))
7319     {
7320         HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7321         surface->resource.heapMemory = NULL;
7322         surface->resource.allocatedMemory = surface->dib.bitmap_data;
7323     }
7324
7325     return hr;
7326 }
7327
7328 HRESULT CDECL wined3d_surface_create(struct wined3d_device *device, UINT width, UINT height,
7329         enum wined3d_format_id format_id, DWORD usage, enum wined3d_pool pool,
7330         enum wined3d_multisample_type multisample_type, DWORD multisample_quality,
7331         enum wined3d_surface_type surface_type, DWORD flags, void *parent,
7332         const struct wined3d_parent_ops *parent_ops, struct wined3d_surface **surface)
7333 {
7334     struct wined3d_surface *object;
7335     HRESULT hr;
7336
7337     TRACE("device %p, width %u, height %u, format %s\n",
7338             device, width, height, debug_d3dformat(format_id));
7339     TRACE("surface %p, usage %s (%#x), pool %s, multisample_type %#x, multisample_quality %u\n",
7340             surface, debug_d3dusage(usage), usage, debug_d3dpool(pool), multisample_type, multisample_quality);
7341     TRACE("surface_type %#x, flags %#x, parent %p, parent_ops %p.\n", surface_type, flags, parent, parent_ops);
7342
7343     if (surface_type == WINED3D_SURFACE_TYPE_OPENGL && !device->adapter)
7344     {
7345         ERR("OpenGL surfaces are not available without OpenGL.\n");
7346         return WINED3DERR_NOTAVAILABLE;
7347     }
7348
7349     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
7350     if (!object)
7351     {
7352         ERR("Failed to allocate surface memory.\n");
7353         return WINED3DERR_OUTOFVIDEOMEMORY;
7354     }
7355
7356     if (FAILED(hr = surface_init(object, surface_type, device->surface_alignment, width, height,
7357             multisample_type, multisample_quality, device, usage, format_id, pool, flags, parent, parent_ops)))
7358     {
7359         WARN("Failed to initialize surface, returning %#x.\n", hr);
7360         HeapFree(GetProcessHeap(), 0, object);
7361         return hr;
7362     }
7363
7364     TRACE("Created surface %p.\n", object);
7365     *surface = object;
7366
7367     return hr;
7368 }