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