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