wined3d: Use "gl_info" in some more places in context_create().
[wine] / dlls / wined3d / surface.c
1 /*
2  * IWineD3DSurface Implementation
3  *
4  * Copyright 1998 Lionel Ulmer
5  * Copyright 2000-2001 TransGaming Technologies Inc.
6  * Copyright 2002-2005 Jason Edmeades
7  * Copyright 2002-2003 Raphael Junqueira
8  * Copyright 2004 Christian Costa
9  * Copyright 2005 Oliver Stieber
10  * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
11  * Copyright 2007-2008 Henri Verbeet
12  * Copyright 2006-2008 Roderick Colenbrander
13  * Copyright 2009 Henri Verbeet for CodeWeavers
14  *
15  * This library is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Lesser General Public
17  * License as published by the Free Software Foundation; either
18  * version 2.1 of the License, or (at your option) any later version.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * Lesser General Public License for more details.
24  *
25  * You should have received a copy of the GNU Lesser General Public
26  * License along with this library; if not, write to the Free Software
27  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28  */
29
30 #include "config.h"
31 #include "wine/port.h"
32 #include "wined3d_private.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
35 WINE_DECLARE_DEBUG_CHANNEL(d3d);
36
37 #define GLINFO_LOCATION (*gl_info)
38
39 static void surface_cleanup(IWineD3DSurfaceImpl *This)
40 {
41     IWineD3DDeviceImpl *device = This->resource.device;
42     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
43     struct wined3d_context *context = NULL;
44     renderbuffer_entry_t *entry, *entry2;
45
46     TRACE("(%p) : Cleaning up.\n", This);
47
48     /* Need a context to destroy the texture. Use the currently active render
49      * target, but only if the primary render target exists. Otherwise
50      * lastActiveRenderTarget is garbage. When destroying the primary render
51      * target, Uninit3D() will activate a context before doing anything. */
52     if (device->render_targets && device->render_targets[0])
53     {
54         context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
55     }
56
57     ENTER_GL();
58
59     if (This->texture_name)
60     {
61         /* Release the OpenGL texture. */
62         TRACE("Deleting texture %u.\n", This->texture_name);
63         glDeleteTextures(1, &This->texture_name);
64     }
65
66     if (This->Flags & SFLAG_PBO)
67     {
68         /* Delete the PBO. */
69         GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
70     }
71
72     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry)
73     {
74         gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
75         HeapFree(GetProcessHeap(), 0, entry);
76     }
77
78     LEAVE_GL();
79
80     if (This->Flags & SFLAG_DIBSECTION)
81     {
82         /* Release the DC. */
83         SelectObject(This->hDC, This->dib.holdbitmap);
84         DeleteDC(This->hDC);
85         /* Release the DIB section. */
86         DeleteObject(This->dib.DIBsection);
87         This->dib.bitmap_data = NULL;
88         This->resource.allocatedMemory = NULL;
89     }
90
91     if (This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem((IWineD3DSurface *)This, NULL);
92     if (This->overlay_dest) list_remove(&This->overlay_entry);
93
94     HeapFree(GetProcessHeap(), 0, This->palette9);
95
96     resource_cleanup((IWineD3DResource *)This);
97
98     if (context) context_release(context);
99 }
100
101 UINT surface_calculate_size(const struct GlPixelFormatDesc *format_desc, UINT alignment, UINT width, UINT height)
102 {
103     UINT size;
104
105     if (format_desc->format == WINED3DFMT_UNKNOWN)
106     {
107         size = 0;
108     }
109     else if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
110     {
111         UINT row_block_count = (width + format_desc->block_width - 1) / format_desc->block_width;
112         UINT row_count = (height + format_desc->block_height - 1) / format_desc->block_height;
113         size = row_count * row_block_count * format_desc->block_byte_count;
114     }
115     else
116     {
117         /* The pitch is a multiple of 4 bytes. */
118         size = height * (((width * format_desc->byte_count) + alignment - 1) & ~(alignment - 1));
119     }
120
121     if (format_desc->heightscale != 0.0f) size *= format_desc->heightscale;
122
123     return size;
124 }
125
126 struct blt_info
127 {
128     GLenum binding;
129     GLenum bind_target;
130     enum tex_types tex_type;
131     GLfloat coords[4][3];
132 };
133
134 struct float_rect
135 {
136     float l;
137     float t;
138     float r;
139     float b;
140 };
141
142 static inline void cube_coords_float(const RECT *r, UINT w, UINT h, struct float_rect *f)
143 {
144     f->l = ((r->left * 2.0f) / w) - 1.0f;
145     f->t = ((r->top * 2.0f) / h) - 1.0f;
146     f->r = ((r->right * 2.0f) / w) - 1.0f;
147     f->b = ((r->bottom * 2.0f) / h) - 1.0f;
148 }
149
150 static void surface_get_blt_info(GLenum target, const RECT *rect_in, GLsizei w, GLsizei h, struct blt_info *info)
151 {
152     GLfloat (*coords)[3] = info->coords;
153     RECT rect;
154     struct float_rect f;
155
156     if (rect_in)
157         rect = *rect_in;
158     else
159     {
160         rect.left = 0;
161         rect.top = 0;
162         rect.right = w;
163         rect.bottom = h;
164     }
165
166     switch (target)
167     {
168         default:
169             FIXME("Unsupported texture target %#x\n", target);
170             /* Fall back to GL_TEXTURE_2D */
171         case GL_TEXTURE_2D:
172             info->binding = GL_TEXTURE_BINDING_2D;
173             info->bind_target = GL_TEXTURE_2D;
174             info->tex_type = tex_2d;
175             coords[0][0] = (float)rect.left / w;
176             coords[0][1] = (float)rect.top / h;
177             coords[0][2] = 0.0f;
178
179             coords[1][0] = (float)rect.right / w;
180             coords[1][1] = (float)rect.top / h;
181             coords[1][2] = 0.0f;
182
183             coords[2][0] = (float)rect.left / w;
184             coords[2][1] = (float)rect.bottom / h;
185             coords[2][2] = 0.0f;
186
187             coords[3][0] = (float)rect.right / w;
188             coords[3][1] = (float)rect.bottom / h;
189             coords[3][2] = 0.0f;
190             break;
191
192         case GL_TEXTURE_RECTANGLE_ARB:
193             info->binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
194             info->bind_target = GL_TEXTURE_RECTANGLE_ARB;
195             info->tex_type = tex_rect;
196             coords[0][0] = rect.left;   coords[0][1] = rect.top;     coords[0][2] = 0.0f;
197             coords[1][0] = rect.right;  coords[1][1] = rect.top;     coords[1][2] = 0.0f;
198             coords[2][0] = rect.left;   coords[2][1] = rect.bottom;  coords[2][2] = 0.0f;
199             coords[3][0] = rect.right;  coords[3][1] = rect.bottom;  coords[3][2] = 0.0f;
200             break;
201
202         case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
203             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
204             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
205             info->tex_type = tex_cube;
206             cube_coords_float(&rect, w, h, &f);
207
208             coords[0][0] =  1.0f;   coords[0][1] = -f.t;   coords[0][2] = -f.l;
209             coords[1][0] =  1.0f;   coords[1][1] = -f.t;   coords[1][2] = -f.r;
210             coords[2][0] =  1.0f;   coords[2][1] = -f.b;   coords[2][2] = -f.l;
211             coords[3][0] =  1.0f;   coords[3][1] = -f.b;   coords[3][2] = -f.r;
212             break;
213
214         case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
215             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
216             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
217             info->tex_type = tex_cube;
218             cube_coords_float(&rect, w, h, &f);
219
220             coords[0][0] = -1.0f;   coords[0][1] = -f.t;   coords[0][2] = f.l;
221             coords[1][0] = -1.0f;   coords[1][1] = -f.t;   coords[1][2] = f.r;
222             coords[2][0] = -1.0f;   coords[2][1] = -f.b;   coords[2][2] = f.l;
223             coords[3][0] = -1.0f;   coords[3][1] = -f.b;   coords[3][2] = f.r;
224             break;
225
226         case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
227             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
228             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
229             info->tex_type = tex_cube;
230             cube_coords_float(&rect, w, h, &f);
231
232             coords[0][0] = f.l;   coords[0][1] =  1.0f;   coords[0][2] = f.t;
233             coords[1][0] = f.r;   coords[1][1] =  1.0f;   coords[1][2] = f.t;
234             coords[2][0] = f.l;   coords[2][1] =  1.0f;   coords[2][2] = f.b;
235             coords[3][0] = f.r;   coords[3][1] =  1.0f;   coords[3][2] = f.b;
236             break;
237
238         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
239             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
240             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
241             info->tex_type = tex_cube;
242             cube_coords_float(&rect, w, h, &f);
243
244             coords[0][0] = f.l;   coords[0][1] = -1.0f;   coords[0][2] = -f.t;
245             coords[1][0] = f.r;   coords[1][1] = -1.0f;   coords[1][2] = -f.t;
246             coords[2][0] = f.l;   coords[2][1] = -1.0f;   coords[2][2] = -f.b;
247             coords[3][0] = f.r;   coords[3][1] = -1.0f;   coords[3][2] = -f.b;
248             break;
249
250         case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
251             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
252             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
253             info->tex_type = tex_cube;
254             cube_coords_float(&rect, w, h, &f);
255
256             coords[0][0] = f.l;   coords[0][1] = -f.t;   coords[0][2] =  1.0f;
257             coords[1][0] = f.r;   coords[1][1] = -f.t;   coords[1][2] =  1.0f;
258             coords[2][0] = f.l;   coords[2][1] = -f.b;   coords[2][2] =  1.0f;
259             coords[3][0] = f.r;   coords[3][1] = -f.b;   coords[3][2] =  1.0f;
260             break;
261
262         case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
263             info->binding = GL_TEXTURE_BINDING_CUBE_MAP_ARB;
264             info->bind_target = GL_TEXTURE_CUBE_MAP_ARB;
265             info->tex_type = tex_cube;
266             cube_coords_float(&rect, w, h, &f);
267
268             coords[0][0] = -f.l;   coords[0][1] = -f.t;   coords[0][2] = -1.0f;
269             coords[1][0] = -f.r;   coords[1][1] = -f.t;   coords[1][2] = -1.0f;
270             coords[2][0] = -f.l;   coords[2][1] = -f.b;   coords[2][2] = -1.0f;
271             coords[3][0] = -f.r;   coords[3][1] = -f.b;   coords[3][2] = -1.0f;
272             break;
273     }
274 }
275
276
277 HRESULT surface_init(IWineD3DSurfaceImpl *surface, WINED3DSURFTYPE surface_type, UINT alignment,
278         UINT width, UINT height, UINT level, BOOL lockable, BOOL discard, WINED3DMULTISAMPLE_TYPE multisample_type,
279         UINT multisample_quality, IWineD3DDeviceImpl *device, DWORD usage, WINED3DFORMAT format,
280         WINED3DPOOL pool, IUnknown *parent, const struct wined3d_parent_ops *parent_ops)
281 {
282     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
283     const struct GlPixelFormatDesc *format_desc = getFormatDescEntry(format, gl_info);
284     void (*cleanup)(IWineD3DSurfaceImpl *This);
285     unsigned int resource_size;
286     HRESULT hr;
287
288     if (multisample_quality > 0)
289     {
290         FIXME("multisample_quality set to %u, substituting 0\n", multisample_quality);
291         multisample_quality = 0;
292     }
293
294     /* FIXME: Check that the format is supported by the device. */
295
296     resource_size = surface_calculate_size(format_desc, alignment, width, height);
297
298     /* Look at the implementation and set the correct Vtable. */
299     switch (surface_type)
300     {
301         case SURFACE_OPENGL:
302             surface->lpVtbl = &IWineD3DSurface_Vtbl;
303             cleanup = surface_cleanup;
304             break;
305
306         case SURFACE_GDI:
307             surface->lpVtbl = &IWineGDISurface_Vtbl;
308             cleanup = surface_gdi_cleanup;
309             break;
310
311         default:
312             ERR("Requested unknown surface implementation %#x.\n", surface_type);
313             return WINED3DERR_INVALIDCALL;
314     }
315
316     hr = resource_init((IWineD3DResource *)surface, WINED3DRTYPE_SURFACE,
317             device, resource_size, usage, format_desc, pool, parent, parent_ops);
318     if (FAILED(hr))
319     {
320         WARN("Failed to initialize resource, returning %#x.\n", hr);
321         return hr;
322     }
323
324     /* "Standalone" surface. */
325     IWineD3DSurface_SetContainer((IWineD3DSurface *)surface, NULL);
326
327     surface->currentDesc.Width = width;
328     surface->currentDesc.Height = height;
329     surface->currentDesc.MultiSampleType = multisample_type;
330     surface->currentDesc.MultiSampleQuality = multisample_quality;
331     surface->texture_level = level;
332     list_init(&surface->overlays);
333
334     /* Flags */
335     surface->Flags = SFLAG_NORMCOORD; /* Default to normalized coords. */
336     if (discard) surface->Flags |= SFLAG_DISCARD;
337     if (lockable || format == WINED3DFMT_D16_LOCKABLE) surface->Flags |= SFLAG_LOCKABLE;
338
339     /* Quick lockable sanity check.
340      * TODO: remove this after surfaces, usage and lockability have been debugged properly
341      * this function is too deep to need to care about things like this.
342      * Levels need to be checked too, since they all affect what can be done. */
343     switch (pool)
344     {
345         case WINED3DPOOL_SCRATCH:
346             if(!lockable)
347             {
348                 FIXME("Called with a pool of SCRATCH and a lockable of FALSE "
349                         "which are mutually exclusive, setting lockable to TRUE.\n");
350                 lockable = TRUE;
351             }
352             break;
353
354         case WINED3DPOOL_SYSTEMMEM:
355             if (!lockable)
356                 FIXME("Called with a pool of SYSTEMMEM and a lockable of FALSE, this is acceptable but unexpected.\n");
357             break;
358
359         case WINED3DPOOL_MANAGED:
360             if (usage & WINED3DUSAGE_DYNAMIC)
361                 FIXME("Called with a pool of MANAGED and a usage of DYNAMIC which are mutually exclusive.\n");
362             break;
363
364         case WINED3DPOOL_DEFAULT:
365             if (lockable && !(usage & (WINED3DUSAGE_DYNAMIC | WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
366                 WARN("Creating a lockable surface with a POOL of DEFAULT, that doesn't specify DYNAMIC usage.\n");
367             break;
368
369         default:
370             FIXME("Unknown pool %#x.\n", pool);
371             break;
372     };
373
374     if (usage & WINED3DUSAGE_RENDERTARGET && pool != WINED3DPOOL_DEFAULT)
375     {
376         FIXME("Trying to create a render target that isn't in the default pool.\n");
377     }
378
379     /* Mark the texture as dirty so that it gets loaded first time around. */
380     surface_add_dirty_rect((IWineD3DSurface *)surface, NULL);
381     list_init(&surface->renderbuffers);
382
383     TRACE("surface %p, memory %p, size %u\n", surface, surface->resource.allocatedMemory, surface->resource.size);
384
385     /* Call the private setup routine */
386     hr = IWineD3DSurface_PrivateSetup((IWineD3DSurface *)surface);
387     if (FAILED(hr))
388     {
389         ERR("Private setup failed, returning %#x\n", hr);
390         cleanup(surface);
391         return hr;
392     }
393
394     return hr;
395 }
396
397 static void surface_force_reload(IWineD3DSurface *iface)
398 {
399     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
400
401     This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
402 }
403
404 void surface_set_texture_name(IWineD3DSurface *iface, GLuint new_name, BOOL srgb)
405 {
406     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
407     GLuint *name;
408     DWORD flag;
409
410     if(srgb)
411     {
412         name = &This->texture_name_srgb;
413         flag = SFLAG_INSRGBTEX;
414     }
415     else
416     {
417         name = &This->texture_name;
418         flag = SFLAG_INTEXTURE;
419     }
420
421     TRACE("(%p) : setting texture name %u\n", This, new_name);
422
423     if (!*name && new_name)
424     {
425         /* FIXME: We shouldn't need to remove SFLAG_INTEXTURE if the
426          * surface has no texture name yet. See if we can get rid of this. */
427         if (This->Flags & flag)
428             ERR("Surface has SFLAG_INTEXTURE set, but no texture name\n");
429         IWineD3DSurface_ModifyLocation(iface, flag, FALSE);
430     }
431
432     *name = new_name;
433     surface_force_reload(iface);
434 }
435
436 void surface_set_texture_target(IWineD3DSurface *iface, GLenum target)
437 {
438     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
439
440     TRACE("(%p) : setting target %#x\n", This, target);
441
442     if (This->texture_target != target)
443     {
444         if (target == GL_TEXTURE_RECTANGLE_ARB)
445         {
446             This->Flags &= ~SFLAG_NORMCOORD;
447         }
448         else if (This->texture_target == GL_TEXTURE_RECTANGLE_ARB)
449         {
450             This->Flags |= SFLAG_NORMCOORD;
451         }
452     }
453     This->texture_target = target;
454     surface_force_reload(iface);
455 }
456
457 /* Context activation is done by the caller. */
458 static void surface_bind_and_dirtify(IWineD3DSurfaceImpl *This, BOOL srgb) {
459     DWORD active_sampler;
460
461     /* We don't need a specific texture unit, but after binding the texture the current unit is dirty.
462      * Read the unit back instead of switching to 0, this avoids messing around with the state manager's
463      * gl states. The current texture unit should always be a valid one.
464      *
465      * To be more specific, this is tricky because we can implicitly be called
466      * from sampler() in state.c. This means we can't touch anything other than
467      * whatever happens to be the currently active texture, or we would risk
468      * marking already applied sampler states dirty again.
469      *
470      * TODO: Track the current active texture per GL context instead of using glGet
471      */
472     GLint active_texture;
473     ENTER_GL();
474     glGetIntegerv(GL_ACTIVE_TEXTURE, &active_texture);
475     LEAVE_GL();
476     active_sampler = This->resource.device->rev_tex_unit_map[active_texture - GL_TEXTURE0_ARB];
477
478     if (active_sampler != WINED3D_UNMAPPED_STAGE)
479     {
480         IWineD3DDeviceImpl_MarkStateDirty(This->resource.device, STATE_SAMPLER(active_sampler));
481     }
482     IWineD3DSurface_BindTexture((IWineD3DSurface *)This, srgb);
483 }
484
485 /* This function checks if the primary render target uses the 8bit paletted format. */
486 static BOOL primary_render_target_is_p8(IWineD3DDeviceImpl *device)
487 {
488     if (device->render_targets && device->render_targets[0]) {
489         IWineD3DSurfaceImpl* render_target = (IWineD3DSurfaceImpl*)device->render_targets[0];
490         if ((render_target->resource.usage & WINED3DUSAGE_RENDERTARGET)
491                 && (render_target->resource.format_desc->format == WINED3DFMT_P8_UINT))
492             return TRUE;
493     }
494     return FALSE;
495 }
496
497 #undef GLINFO_LOCATION
498
499 #define GLINFO_LOCATION This->resource.device->adapter->gl_info
500
501 /* This call just downloads data, the caller is responsible for binding the
502  * correct texture. */
503 /* Context activation is done by the caller. */
504 static void surface_download_data(IWineD3DSurfaceImpl *This) {
505     const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
506
507     /* Only support read back of converted P8 surfaces */
508     if (This->Flags & SFLAG_CONVERTED && format_desc->format != WINED3DFMT_P8_UINT)
509     {
510         FIXME("Read back converted textures unsupported, format=%s\n", debug_d3dformat(format_desc->format));
511         return;
512     }
513
514     ENTER_GL();
515
516     if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
517     {
518         TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p.\n",
519                 This, This->texture_level, format_desc->glFormat, format_desc->glType,
520                 This->resource.allocatedMemory);
521
522         if (This->Flags & SFLAG_PBO)
523         {
524             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
525             checkGLcall("glBindBufferARB");
526             GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target, This->texture_level, NULL));
527             checkGLcall("glGetCompressedTexImageARB");
528             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
529             checkGLcall("glBindBufferARB");
530         }
531         else
532         {
533             GL_EXTCALL(glGetCompressedTexImageARB(This->texture_target,
534                     This->texture_level, This->resource.allocatedMemory));
535             checkGLcall("glGetCompressedTexImageARB");
536         }
537
538         LEAVE_GL();
539     } else {
540         void *mem;
541         GLenum format = format_desc->glFormat;
542         GLenum type = format_desc->glType;
543         int src_pitch = 0;
544         int dst_pitch = 0;
545
546         /* In case of P8 the index is stored in the alpha component if the primary render target uses P8 */
547         if (format_desc->format == WINED3DFMT_P8_UINT && primary_render_target_is_p8(This->resource.device))
548         {
549             format = GL_ALPHA;
550             type = GL_UNSIGNED_BYTE;
551         }
552
553         if (This->Flags & SFLAG_NONPOW2) {
554             unsigned char alignment = This->resource.device->surface_alignment;
555             src_pitch = format_desc->byte_count * This->pow2Width;
556             dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
557             src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
558             mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
559         } else {
560             mem = This->resource.allocatedMemory;
561         }
562
563         TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n",
564                 This, This->texture_level, format, type, mem);
565
566         if(This->Flags & SFLAG_PBO) {
567             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
568             checkGLcall("glBindBufferARB");
569
570             glGetTexImage(This->texture_target, This->texture_level, format, type, NULL);
571             checkGLcall("glGetTexImage");
572
573             GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
574             checkGLcall("glBindBufferARB");
575         } else {
576             glGetTexImage(This->texture_target, This->texture_level, format, type, mem);
577             checkGLcall("glGetTexImage");
578         }
579         LEAVE_GL();
580
581         if (This->Flags & SFLAG_NONPOW2) {
582             const BYTE *src_data;
583             BYTE *dst_data;
584             UINT y;
585             /*
586              * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
587              * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
588              * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
589              *
590              * We're doing this...
591              *
592              * instead of boxing the texture :
593              * |<-texture width ->|  -->pow2width|   /\
594              * |111111111111111111|              |   |
595              * |222 Texture 222222| boxed empty  | texture height
596              * |3333 Data 33333333|              |   |
597              * |444444444444444444|              |   \/
598              * -----------------------------------   |
599              * |     boxed  empty | boxed empty  | pow2height
600              * |                  |              |   \/
601              * -----------------------------------
602              *
603              *
604              * we're repacking the data to the expected texture width
605              *
606              * |<-texture width ->|  -->pow2width|   /\
607              * |111111111111111111222222222222222|   |
608              * |222333333333333333333444444444444| texture height
609              * |444444                           |   |
610              * |                                 |   \/
611              * |                                 |   |
612              * |            empty                | pow2height
613              * |                                 |   \/
614              * -----------------------------------
615              *
616              * == is the same as
617              *
618              * |<-texture width ->|    /\
619              * |111111111111111111|
620              * |222222222222222222|texture height
621              * |333333333333333333|
622              * |444444444444444444|    \/
623              * --------------------
624              *
625              * this also means that any references to allocatedMemory should work with the data as if were a
626              * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
627              *
628              * internally the texture is still stored in a boxed format so any references to textureName will
629              * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
630              *
631              * Performance should not be an issue, because applications normally do not lock the surfaces when
632              * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
633              * and doesn't have to be re-read.
634              */
635             src_data = mem;
636             dst_data = This->resource.allocatedMemory;
637             TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
638             for (y = 1 ; y < This->currentDesc.Height; y++) {
639                 /* skip the first row */
640                 src_data += src_pitch;
641                 dst_data += dst_pitch;
642                 memcpy(dst_data, src_data, dst_pitch);
643             }
644
645             HeapFree(GetProcessHeap(), 0, mem);
646         }
647     }
648
649     /* Surface has now been downloaded */
650     This->Flags |= SFLAG_INSYSMEM;
651 }
652
653 /* This call just uploads data, the caller is responsible for binding the
654  * correct texture. */
655 /* Context activation is done by the caller. */
656 static void surface_upload_data(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data) {
657     const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
658
659     TRACE("This %p, internal %#x, width %d, height %d, format %#x, type %#x, data %p.\n",
660             This, internal, width, height, format, type, data);
661     TRACE("target %#x, level %u, resource size %u.\n",
662             This->texture_target, This->texture_level, This->resource.size);
663
664     if (format_desc->heightscale != 1.0f && format_desc->heightscale != 0.0f) height *= format_desc->heightscale;
665
666     ENTER_GL();
667
668     if (This->Flags & SFLAG_PBO)
669     {
670         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
671         checkGLcall("glBindBufferARB");
672
673         TRACE("(%p) pbo: %#x, data: %p.\n", This, This->pbo, data);
674         data = NULL;
675     }
676
677     if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
678     {
679         TRACE("Calling glCompressedTexSubImage2DARB.\n");
680
681         GL_EXTCALL(glCompressedTexSubImage2DARB(This->texture_target, This->texture_level,
682                 0, 0, width, height, internal, This->resource.size, data));
683         checkGLcall("glCompressedTexSubImage2DARB");
684     }
685     else
686     {
687         TRACE("Calling glTexSubImage2D.\n");
688
689         glTexSubImage2D(This->texture_target, This->texture_level,
690                 0, 0, width, height, format, type, data);
691         checkGLcall("glTexSubImage2D");
692     }
693
694     if (This->Flags & SFLAG_PBO)
695     {
696         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
697         checkGLcall("glBindBufferARB");
698     }
699
700     LEAVE_GL();
701 }
702
703 /* This call just allocates the texture, the caller is responsible for binding
704  * the correct texture. */
705 /* Context activation is done by the caller. */
706 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) {
707     const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
708     const struct GlPixelFormatDesc *format_desc = This->resource.format_desc;
709     BOOL enable_client_storage = FALSE;
710     const BYTE *mem = NULL;
711
712     if (format_desc->heightscale != 1.0f && format_desc->heightscale != 0.0f) height *= format_desc->heightscale;
713
714     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",
715             This, This->texture_target, This->texture_level, debug_d3dformat(format_desc->format),
716             internal, width, height, format, type);
717
718     ENTER_GL();
719
720     if (gl_info->supported[APPLE_CLIENT_STORAGE])
721     {
722         if(This->Flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_CONVERTED) || This->resource.allocatedMemory == NULL) {
723             /* In some cases we want to disable client storage.
724              * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
725              * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
726              * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
727              * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
728              */
729             glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
730             checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
731             This->Flags &= ~SFLAG_CLIENT;
732             enable_client_storage = TRUE;
733         } else {
734             This->Flags |= SFLAG_CLIENT;
735
736             /* Point opengl to our allocated texture memory. Do not use resource.allocatedMemory here because
737              * it might point into a pbo. Instead use heapMemory, but get the alignment right.
738              */
739             mem = (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
740         }
741     }
742
743     if (format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED && mem)
744     {
745         GL_EXTCALL(glCompressedTexImage2DARB(This->texture_target, This->texture_level,
746                 internal, width, height, 0, This->resource.size, mem));
747     }
748     else
749     {
750         glTexImage2D(This->texture_target, This->texture_level,
751                 internal, width, height, 0, format, type, mem);
752         checkGLcall("glTexImage2D");
753     }
754
755     if(enable_client_storage) {
756         glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
757         checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
758     }
759     LEAVE_GL();
760 }
761
762 /* In D3D the depth stencil dimensions have to be greater than or equal to the
763  * render target dimensions. With FBOs, the dimensions have to be an exact match. */
764 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
765 /* GL locking is done by the caller */
766 void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height) {
767     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
768     const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
769     renderbuffer_entry_t *entry;
770     GLuint renderbuffer = 0;
771     unsigned int src_width, src_height;
772
773     src_width = This->pow2Width;
774     src_height = This->pow2Height;
775
776     /* A depth stencil smaller than the render target is not valid */
777     if (width > src_width || height > src_height) return;
778
779     /* Remove any renderbuffer set if the sizes match */
780     if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
781             || (width == src_width && height == src_height))
782     {
783         This->current_renderbuffer = NULL;
784         return;
785     }
786
787     /* Look if we've already got a renderbuffer of the correct dimensions */
788     LIST_FOR_EACH_ENTRY(entry, &This->renderbuffers, renderbuffer_entry_t, entry) {
789         if (entry->width == width && entry->height == height) {
790             renderbuffer = entry->id;
791             This->current_renderbuffer = entry;
792             break;
793         }
794     }
795
796     if (!renderbuffer) {
797         gl_info->fbo_ops.glGenRenderbuffers(1, &renderbuffer);
798         gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
799         gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER,
800                 This->resource.format_desc->glInternal, width, height);
801
802         entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
803         entry->width = width;
804         entry->height = height;
805         entry->id = renderbuffer;
806         list_add_head(&This->renderbuffers, &entry->entry);
807
808         This->current_renderbuffer = entry;
809     }
810
811     checkGLcall("set_compatible_renderbuffer");
812 }
813
814 GLenum surface_get_gl_buffer(IWineD3DSurface *iface)
815 {
816     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
817     IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *)This->container;
818
819     TRACE("iface %p.\n", iface);
820
821     if (!(This->Flags & SFLAG_SWAPCHAIN))
822     {
823         ERR("Surface %p is not on a swapchain.\n", iface);
824         return GL_NONE;
825     }
826
827     if (swapchain->backBuffer && swapchain->backBuffer[0] == iface)
828     {
829         if (swapchain->render_to_fbo)
830         {
831             TRACE("Returning GL_COLOR_ATTACHMENT0\n");
832             return GL_COLOR_ATTACHMENT0;
833         }
834         TRACE("Returning GL_BACK\n");
835         return GL_BACK;
836     }
837     else if (swapchain->frontBuffer == iface)
838     {
839         TRACE("Returning GL_FRONT\n");
840         return GL_FRONT;
841     }
842
843     FIXME("Higher back buffer, returning GL_BACK\n");
844     return GL_BACK;
845 }
846
847 /* Slightly inefficient way to handle multiple dirty rects but it works :) */
848 void surface_add_dirty_rect(IWineD3DSurface *iface, const RECT *dirty_rect)
849 {
850     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
851     IWineD3DBaseTexture *baseTexture = NULL;
852
853     if (!(This->Flags & SFLAG_INSYSMEM) && (This->Flags & SFLAG_INTEXTURE))
854         IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL /* no partial locking for textures yet */);
855
856     IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
857     if (dirty_rect)
858     {
859         This->dirtyRect.left = min(This->dirtyRect.left, dirty_rect->left);
860         This->dirtyRect.top = min(This->dirtyRect.top, dirty_rect->top);
861         This->dirtyRect.right = max(This->dirtyRect.right, dirty_rect->right);
862         This->dirtyRect.bottom = max(This->dirtyRect.bottom, dirty_rect->bottom);
863     }
864     else
865     {
866         This->dirtyRect.left = 0;
867         This->dirtyRect.top = 0;
868         This->dirtyRect.right = This->currentDesc.Width;
869         This->dirtyRect.bottom = This->currentDesc.Height;
870     }
871
872     TRACE("(%p) : Dirty: yes, Rect:(%d, %d, %d, %d)\n", This, This->dirtyRect.left,
873             This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
874
875     /* if the container is a basetexture then mark it dirty. */
876     if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture)))
877     {
878         TRACE("Passing to container\n");
879         IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
880         IWineD3DBaseTexture_Release(baseTexture);
881     }
882 }
883
884 static inline BOOL surface_can_stretch_rect(IWineD3DSurfaceImpl *src, IWineD3DSurfaceImpl *dst)
885 {
886     return ((src->resource.format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE)
887             || (src->resource.usage & WINED3DUSAGE_RENDERTARGET))
888             && ((dst->resource.format_desc->Flags & WINED3DFMT_FLAG_FBO_ATTACHABLE)
889             || (dst->resource.usage & WINED3DUSAGE_RENDERTARGET))
890             && (src->resource.format_desc->format == dst->resource.format_desc->format
891             || (is_identity_fixup(src->resource.format_desc->color_fixup)
892             && is_identity_fixup(dst->resource.format_desc->color_fixup)));
893 }
894
895 static ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface)
896 {
897     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
898     ULONG ref = InterlockedDecrement(&This->resource.ref);
899     TRACE("(%p) : Releasing from %d\n", This, ref + 1);
900
901     if (!ref)
902     {
903         surface_cleanup(This);
904         This->resource.parent_ops->wined3d_object_destroyed(This->resource.parent);
905
906         TRACE("(%p) Released.\n", This);
907         HeapFree(GetProcessHeap(), 0, This);
908     }
909
910     return ref;
911 }
912
913 /* ****************************************************
914    IWineD3DSurface IWineD3DResource parts follow
915    **************************************************** */
916
917 void surface_internal_preload(IWineD3DSurface *iface, enum WINED3DSRGB srgb)
918 {
919     /* TODO: check for locks */
920     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
921     IWineD3DDeviceImpl *device = This->resource.device;
922     IWineD3DBaseTexture *baseTexture = NULL;
923
924     TRACE("(%p)Checking to see if the container is a base texture\n", This);
925     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
926         IWineD3DBaseTextureImpl *tex_impl = (IWineD3DBaseTextureImpl *) baseTexture;
927         TRACE("Passing to container\n");
928         tex_impl->baseTexture.internal_preload(baseTexture, srgb);
929         IWineD3DBaseTexture_Release(baseTexture);
930     } else {
931         struct wined3d_context *context = NULL;
932
933         TRACE("(%p) : About to load surface\n", This);
934
935         if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
936
937         if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
938                 || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
939         {
940             if(palette9_changed(This)) {
941                 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
942                 /* TODO: This is not necessarily needed with hw palettized texture support */
943                 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
944                 /* Make sure the texture is reloaded because of the palette change, this kills performance though :( */
945                 IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
946             }
947         }
948
949         IWineD3DSurface_LoadTexture(iface, srgb == SRGB_SRGB ? TRUE : FALSE);
950
951         if (This->resource.pool == WINED3DPOOL_DEFAULT) {
952             /* Tell opengl to try and keep this texture in video ram (well mostly) */
953             GLclampf tmp;
954             tmp = 0.9f;
955             ENTER_GL();
956             glPrioritizeTextures(1, &This->texture_name, &tmp);
957             LEAVE_GL();
958         }
959
960         if (context) context_release(context);
961     }
962 }
963
964 static void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
965     surface_internal_preload(iface, SRGB_ANY);
966 }
967
968 /* Context activation is done by the caller. */
969 static void surface_remove_pbo(IWineD3DSurfaceImpl *This) {
970     This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
971     This->resource.allocatedMemory =
972             (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
973
974     ENTER_GL();
975     GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
976     checkGLcall("glBindBufferARB(GL_PIXEL_UNPACK_BUFFER, This->pbo)");
977     GL_EXTCALL(glGetBufferSubDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0, This->resource.size, This->resource.allocatedMemory));
978     checkGLcall("glGetBufferSubDataARB");
979     GL_EXTCALL(glDeleteBuffersARB(1, &This->pbo));
980     checkGLcall("glDeleteBuffersARB");
981     LEAVE_GL();
982
983     This->pbo = 0;
984     This->Flags &= ~SFLAG_PBO;
985 }
986
987 BOOL surface_init_sysmem(IWineD3DSurface *iface)
988 {
989     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
990
991     if(!This->resource.allocatedMemory)
992     {
993         This->resource.heapMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + RESOURCE_ALIGNMENT);
994         if(!This->resource.heapMemory)
995         {
996             ERR("Out of memory\n");
997             return FALSE;
998         }
999         This->resource.allocatedMemory =
1000             (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1001     }
1002     else
1003     {
1004         memset(This->resource.allocatedMemory, 0, This->resource.size);
1005     }
1006
1007     IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
1008     return TRUE;
1009 }
1010
1011 static void WINAPI IWineD3DSurfaceImpl_UnLoad(IWineD3DSurface *iface) {
1012     IWineD3DBaseTexture *texture = NULL;
1013     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1014     IWineD3DDeviceImpl *device = This->resource.device;
1015     const struct wined3d_gl_info *gl_info;
1016     renderbuffer_entry_t *entry, *entry2;
1017     struct wined3d_context *context;
1018
1019     TRACE("(%p)\n", iface);
1020
1021     if(This->resource.pool == WINED3DPOOL_DEFAULT) {
1022         /* Default pool resources are supposed to be destroyed before Reset is called.
1023          * Implicit resources stay however. So this means we have an implicit render target
1024          * or depth stencil. The content may be destroyed, but we still have to tear down
1025          * opengl resources, so we cannot leave early.
1026          *
1027          * Put the surfaces into sysmem, and reset the content. The D3D content is undefined,
1028          * but we can't set the sysmem INDRAWABLE because when we're rendering the swapchain
1029          * or the depth stencil into an FBO the texture or render buffer will be removed
1030          * and all flags get lost
1031          */
1032         surface_init_sysmem(iface);
1033     } else {
1034         /* Load the surface into system memory */
1035         IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
1036         IWineD3DSurface_ModifyLocation(iface, SFLAG_INDRAWABLE, FALSE);
1037     }
1038     IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
1039     IWineD3DSurface_ModifyLocation(iface, SFLAG_INSRGBTEX, FALSE);
1040     This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
1041
1042     context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1043     gl_info = context->gl_info;
1044
1045     /* Destroy PBOs, but load them into real sysmem before */
1046     if(This->Flags & SFLAG_PBO) {
1047         surface_remove_pbo(This);
1048     }
1049
1050     /* Destroy fbo render buffers. This is needed for implicit render targets, for
1051      * all application-created targets the application has to release the surface
1052      * before calling _Reset
1053      */
1054     LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry) {
1055         ENTER_GL();
1056         gl_info->fbo_ops.glDeleteRenderbuffers(1, &entry->id);
1057         LEAVE_GL();
1058         list_remove(&entry->entry);
1059         HeapFree(GetProcessHeap(), 0, entry);
1060     }
1061     list_init(&This->renderbuffers);
1062     This->current_renderbuffer = NULL;
1063
1064     /* If we're in a texture, the texture name belongs to the texture. Otherwise,
1065      * destroy it
1066      */
1067     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **) &texture);
1068     if(!texture) {
1069         ENTER_GL();
1070         glDeleteTextures(1, &This->texture_name);
1071         This->texture_name = 0;
1072         glDeleteTextures(1, &This->texture_name_srgb);
1073         This->texture_name_srgb = 0;
1074         LEAVE_GL();
1075     } else {
1076         IWineD3DBaseTexture_Release(texture);
1077     }
1078
1079     context_release(context);
1080 }
1081
1082 /* ******************************************************
1083    IWineD3DSurface IWineD3DSurface parts follow
1084    ****************************************************** */
1085
1086 /* Read the framebuffer back into the surface */
1087 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, const RECT *rect, void *dest, UINT pitch)
1088 {
1089     IWineD3DDeviceImpl *myDevice = This->resource.device;
1090     struct wined3d_context *context;
1091     BYTE *mem;
1092     GLint fmt;
1093     GLint type;
1094     BYTE *row, *top, *bottom;
1095     int i;
1096     BOOL bpp;
1097     RECT local_rect;
1098     BOOL srcIsUpsideDown;
1099     GLint rowLen = 0;
1100     GLint skipPix = 0;
1101     GLint skipRow = 0;
1102
1103     if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1104         static BOOL warned = FALSE;
1105         if(!warned) {
1106             ERR("The application tries to lock the render target, but render target locking is disabled\n");
1107             warned = TRUE;
1108         }
1109         return;
1110     }
1111
1112     /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
1113      * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
1114      * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
1115      * context->last_was_blit set on the unlock.
1116      */
1117     context = context_acquire(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
1118     ENTER_GL();
1119
1120     /* Select the correct read buffer, and give some debug output.
1121      * There is no need to keep track of the current read buffer or reset it, every part of the code
1122      * that reads sets the read buffer as desired.
1123      */
1124     if (surface_is_offscreen((IWineD3DSurface *) This))
1125     {
1126         /* Locking the primary render target which is not on a swapchain(=offscreen render target).
1127          * Read from the back buffer
1128          */
1129         TRACE("Locking offscreen render target\n");
1130         glReadBuffer(myDevice->offscreenBuffer);
1131         srcIsUpsideDown = TRUE;
1132     }
1133     else
1134     {
1135         /* Onscreen surfaces are always part of a swapchain */
1136         GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
1137         TRACE("Locking %#x buffer\n", buffer);
1138         glReadBuffer(buffer);
1139         checkGLcall("glReadBuffer");
1140         srcIsUpsideDown = FALSE;
1141     }
1142
1143     /* TODO: Get rid of the extra rectangle comparison and construction of a full surface rectangle */
1144     if(!rect) {
1145         local_rect.left = 0;
1146         local_rect.top = 0;
1147         local_rect.right = This->currentDesc.Width;
1148         local_rect.bottom = This->currentDesc.Height;
1149     } else {
1150         local_rect = *rect;
1151     }
1152     /* TODO: Get rid of the extra GetPitch call, LockRect does that too. Cache the pitch */
1153
1154     switch(This->resource.format_desc->format)
1155     {
1156         case WINED3DFMT_P8_UINT:
1157         {
1158             if(primary_render_target_is_p8(myDevice)) {
1159                 /* In case of P8 render targets the index is stored in the alpha component */
1160                 fmt = GL_ALPHA;
1161                 type = GL_UNSIGNED_BYTE;
1162                 mem = dest;
1163                 bpp = This->resource.format_desc->byte_count;
1164             } else {
1165                 /* GL can't return palettized data, so read ARGB pixels into a
1166                  * separate block of memory and convert them into palettized format
1167                  * in software. Slow, but if the app means to use palettized render
1168                  * targets and locks it...
1169                  *
1170                  * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
1171                  * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
1172                  * for the color channels when palettizing the colors.
1173                  */
1174                 fmt = GL_RGB;
1175                 type = GL_UNSIGNED_BYTE;
1176                 pitch *= 3;
1177                 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
1178                 if(!mem) {
1179                     ERR("Out of memory\n");
1180                     LEAVE_GL();
1181                     return;
1182                 }
1183                 bpp = This->resource.format_desc->byte_count * 3;
1184             }
1185         }
1186         break;
1187
1188         default:
1189             mem = dest;
1190             fmt = This->resource.format_desc->glFormat;
1191             type = This->resource.format_desc->glType;
1192             bpp = This->resource.format_desc->byte_count;
1193     }
1194
1195     if(This->Flags & SFLAG_PBO) {
1196         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, This->pbo));
1197         checkGLcall("glBindBufferARB");
1198         if(mem != NULL) {
1199             ERR("mem not null for pbo -- unexpected\n");
1200             mem = NULL;
1201         }
1202     }
1203
1204     /* Save old pixel store pack state */
1205     glGetIntegerv(GL_PACK_ROW_LENGTH, &rowLen);
1206     checkGLcall("glGetIntegerv");
1207     glGetIntegerv(GL_PACK_SKIP_PIXELS, &skipPix);
1208     checkGLcall("glGetIntegerv");
1209     glGetIntegerv(GL_PACK_SKIP_ROWS, &skipRow);
1210     checkGLcall("glGetIntegerv");
1211
1212     /* Setup pixel store pack state -- to glReadPixels into the correct place */
1213     glPixelStorei(GL_PACK_ROW_LENGTH, This->currentDesc.Width);
1214     checkGLcall("glPixelStorei");
1215     glPixelStorei(GL_PACK_SKIP_PIXELS, local_rect.left);
1216     checkGLcall("glPixelStorei");
1217     glPixelStorei(GL_PACK_SKIP_ROWS, local_rect.top);
1218     checkGLcall("glPixelStorei");
1219
1220     glReadPixels(local_rect.left, (!srcIsUpsideDown) ? (This->currentDesc.Height - local_rect.bottom) : local_rect.top ,
1221                  local_rect.right - local_rect.left,
1222                  local_rect.bottom - local_rect.top,
1223                  fmt, type, mem);
1224     checkGLcall("glReadPixels");
1225
1226     /* Reset previous pixel store pack state */
1227     glPixelStorei(GL_PACK_ROW_LENGTH, rowLen);
1228     checkGLcall("glPixelStorei");
1229     glPixelStorei(GL_PACK_SKIP_PIXELS, skipPix);
1230     checkGLcall("glPixelStorei");
1231     glPixelStorei(GL_PACK_SKIP_ROWS, skipRow);
1232     checkGLcall("glPixelStorei");
1233
1234     if(This->Flags & SFLAG_PBO) {
1235         GL_EXTCALL(glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0));
1236         checkGLcall("glBindBufferARB");
1237
1238         /* Check if we need to flip the image. If we need to flip use glMapBufferARB
1239          * to get a pointer to it and perform the flipping in software. This is a lot
1240          * faster than calling glReadPixels for each line. In case we want more speed
1241          * we should rerender it flipped in a FBO and read the data back from the FBO. */
1242         if(!srcIsUpsideDown) {
1243             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1244             checkGLcall("glBindBufferARB");
1245
1246             mem = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1247             checkGLcall("glMapBufferARB");
1248         }
1249     }
1250
1251     /* TODO: Merge this with the palettization loop below for P8 targets */
1252     if(!srcIsUpsideDown) {
1253         UINT len, off;
1254         /* glReadPixels returns the image upside down, and there is no way to prevent this.
1255             Flip the lines in software */
1256         len = (local_rect.right - local_rect.left) * bpp;
1257         off = local_rect.left * bpp;
1258
1259         row = HeapAlloc(GetProcessHeap(), 0, len);
1260         if(!row) {
1261             ERR("Out of memory\n");
1262             if (This->resource.format_desc->format == WINED3DFMT_P8_UINT) HeapFree(GetProcessHeap(), 0, mem);
1263             LEAVE_GL();
1264             return;
1265         }
1266
1267         top = mem + pitch * local_rect.top;
1268         bottom = mem + pitch * (local_rect.bottom - 1);
1269         for(i = 0; i < (local_rect.bottom - local_rect.top) / 2; i++) {
1270             memcpy(row, top + off, len);
1271             memcpy(top + off, bottom + off, len);
1272             memcpy(bottom + off, row, len);
1273             top += pitch;
1274             bottom -= pitch;
1275         }
1276         HeapFree(GetProcessHeap(), 0, row);
1277
1278         /* Unmap the temp PBO buffer */
1279         if(This->Flags & SFLAG_PBO) {
1280             GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1281             GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1282         }
1283     }
1284
1285     LEAVE_GL();
1286     context_release(context);
1287
1288     /* For P8 textures we need to perform an inverse palette lookup. This is done by searching for a palette
1289      * index which matches the RGB value. Note this isn't guaranteed to work when there are multiple entries for
1290      * the same color but we have no choice.
1291      * In case of P8 render targets, the index is stored in the alpha component so no conversion is needed.
1292      */
1293     if (This->resource.format_desc->format == WINED3DFMT_P8_UINT && !primary_render_target_is_p8(myDevice))
1294     {
1295         const PALETTEENTRY *pal = NULL;
1296         DWORD width = pitch / 3;
1297         int x, y, c;
1298
1299         if(This->palette) {
1300             pal = This->palette->palents;
1301         } else {
1302             ERR("Palette is missing, cannot perform inverse palette lookup\n");
1303             HeapFree(GetProcessHeap(), 0, mem);
1304             return ;
1305         }
1306
1307         for(y = local_rect.top; y < local_rect.bottom; y++) {
1308             for(x = local_rect.left; x < local_rect.right; x++) {
1309                 /*                      start              lines            pixels      */
1310                 const BYTE *blue = mem + y * pitch + x * (sizeof(BYTE) * 3);
1311                 const BYTE *green = blue  + 1;
1312                 const BYTE *red = green + 1;
1313
1314                 for(c = 0; c < 256; c++) {
1315                     if(*red   == pal[c].peRed   &&
1316                        *green == pal[c].peGreen &&
1317                        *blue  == pal[c].peBlue)
1318                     {
1319                         *((BYTE *) dest + y * width + x) = c;
1320                         break;
1321                     }
1322                 }
1323             }
1324         }
1325         HeapFree(GetProcessHeap(), 0, mem);
1326     }
1327 }
1328
1329 /* Read the framebuffer contents into a texture */
1330 static void read_from_framebuffer_texture(IWineD3DSurfaceImpl *This, BOOL srgb)
1331 {
1332     IWineD3DDeviceImpl *device = This->resource.device;
1333     struct wined3d_context *context;
1334     int bpp;
1335     GLenum format, internal, type;
1336     CONVERT_TYPES convert;
1337     GLint prevRead;
1338     BOOL alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
1339
1340     d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, srgb);
1341
1342     /* Activate the surface to read from. In some situations it isn't the currently active target(e.g. backbuffer
1343      * locking during offscreen rendering). RESOURCELOAD is ok because glCopyTexSubImage2D isn't affected by any
1344      * states in the stateblock, and no driver was found yet that had bugs in that regard.
1345      */
1346     context = context_acquire(device, (IWineD3DSurface *) This, CTXUSAGE_RESOURCELOAD);
1347     surface_bind_and_dirtify(This, srgb);
1348
1349     ENTER_GL();
1350     glGetIntegerv(GL_READ_BUFFER, &prevRead);
1351     LEAVE_GL();
1352
1353     /* Select the correct read buffer, and give some debug output.
1354      * There is no need to keep track of the current read buffer or reset it, every part of the code
1355      * that reads sets the read buffer as desired.
1356      */
1357     if (!surface_is_offscreen((IWineD3DSurface *)This))
1358     {
1359         GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
1360         TRACE("Locking %#x buffer\n", buffer);
1361
1362         ENTER_GL();
1363         glReadBuffer(buffer);
1364         checkGLcall("glReadBuffer");
1365         LEAVE_GL();
1366     }
1367     else
1368     {
1369         /* Locking the primary render target which is not on a swapchain(=offscreen render target).
1370          * Read from the back buffer
1371          */
1372         TRACE("Locking offscreen render target\n");
1373         ENTER_GL();
1374         glReadBuffer(device->offscreenBuffer);
1375         checkGLcall("glReadBuffer");
1376         LEAVE_GL();
1377     }
1378
1379     if(!(This->Flags & alloc_flag)) {
1380         surface_allocate_surface(This, internal, This->pow2Width,
1381                                  This->pow2Height, format, type);
1382         This->Flags |= alloc_flag;
1383     }
1384
1385     ENTER_GL();
1386     /* If !SrcIsUpsideDown we should flip the surface.
1387      * This can be done using glCopyTexSubImage2D but this
1388      * is VERY slow, so don't do that. We should prevent
1389      * this code from getting called in such cases or perhaps
1390      * we can use FBOs */
1391
1392     glCopyTexSubImage2D(This->texture_target, This->texture_level,
1393             0, 0, 0, 0, This->currentDesc.Width, This->currentDesc.Height);
1394     checkGLcall("glCopyTexSubImage2D");
1395
1396     glReadBuffer(prevRead);
1397     checkGLcall("glReadBuffer");
1398
1399     LEAVE_GL();
1400
1401     context_release(context);
1402
1403     TRACE("Updated target %d\n", This->texture_target);
1404 }
1405
1406 /* Context activation is done by the caller. */
1407 void surface_prepare_texture(IWineD3DSurfaceImpl *surface, BOOL srgb)
1408 {
1409     DWORD alloc_flag = srgb ? SFLAG_SRGBALLOCATED : SFLAG_ALLOCATED;
1410     GLenum format, internal, type;
1411     GLsizei width, height;
1412     CONVERT_TYPES convert;
1413     int bpp;
1414
1415     if (surface->Flags & alloc_flag) return;
1416
1417     d3dfmt_get_conv(surface, TRUE, TRUE, &format, &internal, &type, &convert, &bpp, srgb);
1418     if(convert != NO_CONVERSION) surface->Flags |= SFLAG_CONVERTED;
1419     else surface->Flags &= ~SFLAG_CONVERTED;
1420
1421     if (surface->Flags & SFLAG_NONPOW2)
1422     {
1423         width = surface->pow2Width;
1424         height = surface->pow2Height;
1425     }
1426     else
1427     {
1428         width = surface->glRect.right - surface->glRect.left;
1429         height = surface->glRect.bottom - surface->glRect.top;
1430     }
1431
1432     surface_bind_and_dirtify(surface, srgb);
1433     surface_allocate_surface(surface, internal, width, height, format, type);
1434     surface->Flags |= alloc_flag;
1435 }
1436
1437 static void surface_prepare_system_memory(IWineD3DSurfaceImpl *This)
1438 {
1439     IWineD3DDeviceImpl *device = This->resource.device;
1440     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1441
1442     /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
1443      * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
1444      * changed
1445      */
1446     if(!(This->Flags & SFLAG_DYNLOCK)) {
1447         This->lockCount++;
1448         /* MAXLOCKCOUNT is defined in wined3d_private.h */
1449         if(This->lockCount > MAXLOCKCOUNT) {
1450             TRACE("Surface is locked regularly, not freeing the system memory copy any more\n");
1451             This->Flags |= SFLAG_DYNLOCK;
1452         }
1453     }
1454
1455     /* Create a PBO for dynamically locked surfaces but don't do it for converted or non-pow2 surfaces.
1456      * Also don't create a PBO for systemmem surfaces.
1457      */
1458     if (gl_info->supported[ARB_PIXEL_BUFFER_OBJECT] && (This->Flags & SFLAG_DYNLOCK)
1459             && !(This->Flags & (SFLAG_PBO | SFLAG_CONVERTED | SFLAG_NONPOW2))
1460             && (This->resource.pool != WINED3DPOOL_SYSTEMMEM))
1461     {
1462         GLenum error;
1463         struct wined3d_context *context;
1464
1465         context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
1466         ENTER_GL();
1467
1468         GL_EXTCALL(glGenBuffersARB(1, &This->pbo));
1469         error = glGetError();
1470         if(This->pbo == 0 || error != GL_NO_ERROR) {
1471             ERR("Failed to bind the PBO with error %s (%#x)\n", debug_glerror(error), error);
1472         }
1473
1474         TRACE("Attaching pbo=%#x to (%p)\n", This->pbo, This);
1475
1476         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1477         checkGLcall("glBindBufferARB");
1478
1479         GL_EXTCALL(glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->resource.size + 4, This->resource.allocatedMemory, GL_STREAM_DRAW_ARB));
1480         checkGLcall("glBufferDataARB");
1481
1482         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1483         checkGLcall("glBindBufferARB");
1484
1485         /* We don't need the system memory anymore and we can't even use it for PBOs */
1486         if(!(This->Flags & SFLAG_CLIENT)) {
1487             HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
1488             This->resource.heapMemory = NULL;
1489         }
1490         This->resource.allocatedMemory = NULL;
1491         This->Flags |= SFLAG_PBO;
1492         LEAVE_GL();
1493         context_release(context);
1494     }
1495     else if (!(This->resource.allocatedMemory || This->Flags & SFLAG_PBO))
1496     {
1497         /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy,
1498          * or a pbo to map
1499          */
1500         if(!This->resource.heapMemory) {
1501             This->resource.heapMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + RESOURCE_ALIGNMENT);
1502         }
1503         This->resource.allocatedMemory =
1504                 (BYTE *)(((ULONG_PTR) This->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1));
1505         if(This->Flags & SFLAG_INSYSMEM) {
1506             ERR("Surface without memory or pbo has SFLAG_INSYSMEM set!\n");
1507         }
1508     }
1509 }
1510
1511 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
1512     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1513     IWineD3DDeviceImpl *myDevice = This->resource.device;
1514     const RECT *pass_rect = pRect;
1515
1516     TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
1517
1518     /* This is also done in the base class, but we have to verify this before loading any data from
1519      * gl into the sysmem copy. The PBO may be mapped, a different rectangle locked, the discard flag
1520      * may interfere, and all other bad things may happen
1521      */
1522     if (This->Flags & SFLAG_LOCKED) {
1523         WARN("Surface is already locked, returning D3DERR_INVALIDCALL\n");
1524         return WINED3DERR_INVALIDCALL;
1525     }
1526     This->Flags |= SFLAG_LOCKED;
1527
1528     if (!(This->Flags & SFLAG_LOCKABLE))
1529     {
1530         TRACE("Warning: trying to lock unlockable surf@%p\n", This);
1531     }
1532
1533     if (Flags & WINED3DLOCK_DISCARD) {
1534         /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */
1535         TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n");
1536         surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1537         This->Flags |= SFLAG_INSYSMEM;
1538         goto lock_end;
1539     }
1540
1541     if (This->Flags & SFLAG_INSYSMEM) {
1542         TRACE("Local copy is up to date, not downloading data\n");
1543         surface_prepare_system_memory(This); /* Makes sure memory is allocated */
1544         goto lock_end;
1545     }
1546
1547     /* IWineD3DSurface_LoadLocation() does not check if the rectangle specifies
1548      * the full surface. Most callers don't need that, so do it here. */
1549     if (pRect && pRect->top == 0 && pRect->left == 0
1550             && pRect->right == This->currentDesc.Width
1551             && pRect->bottom == This->currentDesc.Height)
1552     {
1553         pass_rect = NULL;
1554     }
1555
1556     if (!(wined3d_settings.rendertargetlock_mode == RTL_DISABLE
1557             && ((This->Flags & SFLAG_SWAPCHAIN) || iface == myDevice->render_targets[0])))
1558     {
1559         IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, pass_rect);
1560     }
1561
1562 lock_end:
1563     if (This->Flags & SFLAG_PBO)
1564     {
1565         struct wined3d_context *context;
1566
1567         context = context_acquire(myDevice, NULL, CTXUSAGE_RESOURCELOAD);
1568         ENTER_GL();
1569         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1570         checkGLcall("glBindBufferARB");
1571
1572         /* This shouldn't happen but could occur if some other function didn't handle the PBO properly */
1573         if(This->resource.allocatedMemory) {
1574             ERR("The surface already has PBO memory allocated!\n");
1575         }
1576
1577         This->resource.allocatedMemory = GL_EXTCALL(glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_READ_WRITE_ARB));
1578         checkGLcall("glMapBufferARB");
1579
1580         /* Make sure the pbo isn't set anymore in order not to break non-pbo calls */
1581         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1582         checkGLcall("glBindBufferARB");
1583
1584         LEAVE_GL();
1585         context_release(context);
1586     }
1587
1588     if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
1589         /* Don't dirtify */
1590     } else {
1591         IWineD3DBaseTexture *pBaseTexture;
1592         /**
1593          * Dirtify on lock
1594          * as seen in msdn docs
1595          */
1596         surface_add_dirty_rect(iface, pRect);
1597
1598         /** Dirtify Container if needed */
1599         if (SUCCEEDED(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture))) {
1600             TRACE("Making container dirty\n");
1601             IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
1602             IWineD3DBaseTexture_Release(pBaseTexture);
1603         } else {
1604             TRACE("Surface is standalone, no need to dirty the container\n");
1605         }
1606     }
1607
1608     return IWineD3DBaseSurfaceImpl_LockRect(iface, pLockedRect, pRect, Flags);
1609 }
1610
1611 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This, GLenum fmt, GLenum type, UINT bpp, const BYTE *mem) {
1612     GLint  prev_store;
1613     GLint  prev_rasterpos[4];
1614     GLint skipBytes = 0;
1615     UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);    /* target is argb, 4 byte */
1616     IWineD3DDeviceImpl *myDevice = This->resource.device;
1617     struct wined3d_context *context;
1618
1619     /* Activate the correct context for the render target */
1620     context = context_acquire(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
1621     ENTER_GL();
1622
1623     if (!surface_is_offscreen((IWineD3DSurface *)This))
1624     {
1625         GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This);
1626         TRACE("Unlocking %#x buffer.\n", buffer);
1627         context_set_draw_buffer(context, buffer);
1628     }
1629     else
1630     {
1631         /* Primary offscreen render target */
1632         TRACE("Offscreen render target.\n");
1633         context_set_draw_buffer(context, myDevice->offscreenBuffer);
1634     }
1635
1636     glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
1637     checkGLcall("glGetIntegerv");
1638     glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
1639     checkGLcall("glGetIntegerv");
1640     glPixelZoom(1.0f, -1.0f);
1641     checkGLcall("glPixelZoom");
1642
1643     /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
1644     glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
1645     glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
1646
1647     glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
1648     checkGLcall("glRasterPos3i");
1649
1650     /* Some drivers(radeon dri, others?) don't like exceptions during
1651      * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
1652      * after ReleaseDC. Reading it will cause an exception, which x11drv will
1653      * catch to put the dib section in InSync mode, which leads to a crash
1654      * and a blocked x server on my radeon card.
1655      *
1656      * The following lines read the dib section so it is put in InSync mode
1657      * before glDrawPixels is called and the crash is prevented. There won't
1658      * be any interfering gdi accesses, because UnlockRect is called from
1659      * ReleaseDC, and the app won't use the dc any more afterwards.
1660      */
1661     if((This->Flags & SFLAG_DIBSECTION) && !(This->Flags & SFLAG_PBO)) {
1662         volatile BYTE read;
1663         read = This->resource.allocatedMemory[0];
1664     }
1665
1666     if(This->Flags & SFLAG_PBO) {
1667         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1668         checkGLcall("glBindBufferARB");
1669     }
1670
1671     /* When the surface is locked we only have to refresh the locked part else we need to update the whole image */
1672     if(This->Flags & SFLAG_LOCKED) {
1673         glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1674                      (This->lockedRect.bottom - This->lockedRect.top)-1,
1675                      fmt, type,
1676                      mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
1677         checkGLcall("glDrawPixels");
1678     } else {
1679         glDrawPixels(This->currentDesc.Width,
1680                      This->currentDesc.Height,
1681                      fmt, type, mem);
1682         checkGLcall("glDrawPixels");
1683     }
1684
1685     if(This->Flags & SFLAG_PBO) {
1686         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1687         checkGLcall("glBindBufferARB");
1688     }
1689
1690     glPixelZoom(1.0f, 1.0f);
1691     checkGLcall("glPixelZoom");
1692
1693     glRasterPos3iv(&prev_rasterpos[0]);
1694     checkGLcall("glRasterPos3iv");
1695
1696     /* Reset to previous pack row length */
1697     glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1698     checkGLcall("glPixelStorei(GL_UNPACK_ROW_LENGTH)");
1699
1700     LEAVE_GL();
1701     context_release(context);
1702 }
1703
1704 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1705     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1706     IWineD3DDeviceImpl *myDevice = This->resource.device;
1707     BOOL fullsurface;
1708
1709     if (!(This->Flags & SFLAG_LOCKED)) {
1710         WARN("trying to Unlock an unlocked surf@%p\n", This);
1711         return WINEDDERR_NOTLOCKED;
1712     }
1713
1714     if (This->Flags & SFLAG_PBO)
1715     {
1716         struct wined3d_context *context;
1717
1718         TRACE("Freeing PBO memory\n");
1719
1720         context = context_acquire(myDevice, NULL, CTXUSAGE_RESOURCELOAD);
1721         ENTER_GL();
1722         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, This->pbo));
1723         GL_EXTCALL(glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB));
1724         GL_EXTCALL(glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0));
1725         checkGLcall("glUnmapBufferARB");
1726         LEAVE_GL();
1727         context_release(context);
1728
1729         This->resource.allocatedMemory = NULL;
1730     }
1731
1732     TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1733
1734     if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
1735         TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1736         goto unlock_end;
1737     }
1738
1739     if ((This->Flags & SFLAG_SWAPCHAIN) || (myDevice->render_targets && iface == myDevice->render_targets[0]))
1740     {
1741         if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1742             static BOOL warned = FALSE;
1743             if(!warned) {
1744                 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1745                 warned = TRUE;
1746             }
1747             goto unlock_end;
1748         }
1749
1750         if(This->dirtyRect.left   == 0 &&
1751            This->dirtyRect.top    == 0 &&
1752            This->dirtyRect.right  == This->currentDesc.Width &&
1753            This->dirtyRect.bottom == This->currentDesc.Height) {
1754             fullsurface = TRUE;
1755         } else {
1756             /* TODO: Proper partial rectangle tracking */
1757             fullsurface = FALSE;
1758             This->Flags |= SFLAG_INSYSMEM;
1759         }
1760
1761         switch(wined3d_settings.rendertargetlock_mode) {
1762             case RTL_READTEX:
1763                 IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL /* partial texture loading not supported yet */);
1764                 /* drop through */
1765
1766             case RTL_READDRAW:
1767                 IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, fullsurface ? NULL : &This->dirtyRect);
1768                 break;
1769         }
1770
1771         if(!fullsurface) {
1772             /* Partial rectangle tracking is not commonly implemented, it is only done for render targets. Overwrite
1773              * the flags to bring them back into a sane state. INSYSMEM was set before to tell LoadLocation where
1774              * to read the rectangle from. Indrawable is set because all modifications from the partial sysmem copy
1775              * are written back to the drawable, thus the surface is merged again in the drawable. The sysmem copy is
1776              * not fully up to date because only a subrectangle was read in LockRect.
1777              */
1778             This->Flags &= ~SFLAG_INSYSMEM;
1779             This->Flags |= SFLAG_INDRAWABLE;
1780         }
1781
1782         This->dirtyRect.left   = This->currentDesc.Width;
1783         This->dirtyRect.top    = This->currentDesc.Height;
1784         This->dirtyRect.right  = 0;
1785         This->dirtyRect.bottom = 0;
1786     } else if(iface == myDevice->stencilBufferTarget) {
1787         FIXME("Depth Stencil buffer locking is not implemented\n");
1788     } else {
1789         /* The rest should be a normal texture */
1790         IWineD3DBaseTextureImpl *impl;
1791         /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1792          * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1793          * states need resetting
1794          */
1795         if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1796             if(impl->baseTexture.bindCount) {
1797                 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1798             }
1799             IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1800         }
1801     }
1802
1803     unlock_end:
1804     This->Flags &= ~SFLAG_LOCKED;
1805     memset(&This->lockedRect, 0, sizeof(RECT));
1806
1807     /* Overlays have to be redrawn manually after changes with the GL implementation */
1808     if(This->overlay_dest) {
1809         IWineD3DSurface_DrawOverlay(iface);
1810     }
1811     return WINED3D_OK;
1812 }
1813
1814 static void surface_release_client_storage(IWineD3DSurface *iface)
1815 {
1816     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
1817     struct wined3d_context *context;
1818
1819     context = context_acquire(This->resource.device, NULL, CTXUSAGE_RESOURCELOAD);
1820
1821     ENTER_GL();
1822     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1823     if(This->texture_name)
1824     {
1825         surface_bind_and_dirtify(This, FALSE);
1826         glTexImage2D(This->texture_target, This->texture_level,
1827                      GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
1828     }
1829     if(This->texture_name_srgb)
1830     {
1831         surface_bind_and_dirtify(This, TRUE);
1832         glTexImage2D(This->texture_target, This->texture_level,
1833                      GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
1834     }
1835     glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1836
1837     LEAVE_GL();
1838     context_release(context);
1839
1840     IWineD3DSurface_ModifyLocation(iface, SFLAG_INSRGBTEX, FALSE);
1841     IWineD3DSurface_ModifyLocation(iface, SFLAG_INTEXTURE, FALSE);
1842     surface_force_reload(iface);
1843 }
1844
1845 static HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC)
1846 {
1847     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1848     WINED3DLOCKED_RECT lock;
1849     HRESULT hr;
1850     RGBQUAD col[256];
1851
1852     TRACE("(%p)->(%p)\n",This,pHDC);
1853
1854     if(This->Flags & SFLAG_USERPTR) {
1855         ERR("Not supported on surfaces with an application-provided surfaces\n");
1856         return WINEDDERR_NODC;
1857     }
1858
1859     /* Give more detailed info for ddraw */
1860     if (This->Flags & SFLAG_DCINUSE)
1861         return WINEDDERR_DCALREADYCREATED;
1862
1863     /* Can't GetDC if the surface is locked */
1864     if (This->Flags & SFLAG_LOCKED)
1865         return WINED3DERR_INVALIDCALL;
1866
1867     memset(&lock, 0, sizeof(lock)); /* To be sure */
1868
1869     /* Create a DIB section if there isn't a hdc yet */
1870     if(!This->hDC) {
1871         if(This->Flags & SFLAG_CLIENT) {
1872             IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
1873             surface_release_client_storage(iface);
1874         }
1875         hr = IWineD3DBaseSurfaceImpl_CreateDIBSection(iface);
1876         if(FAILED(hr)) return WINED3DERR_INVALIDCALL;
1877
1878         /* Use the dib section from now on if we are not using a PBO */
1879         if(!(This->Flags & SFLAG_PBO))
1880             This->resource.allocatedMemory = This->dib.bitmap_data;
1881     }
1882
1883     /* Lock the surface */
1884     hr = IWineD3DSurface_LockRect(iface,
1885                                   &lock,
1886                                   NULL,
1887                                   0);
1888
1889     if(This->Flags & SFLAG_PBO) {
1890         /* Sync the DIB with the PBO. This can't be done earlier because LockRect activates the allocatedMemory */
1891         memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, This->dib.bitmap_size);
1892     }
1893
1894     if(FAILED(hr)) {
1895         ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1896         /* keep the dib section */
1897         return hr;
1898     }
1899
1900     if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
1901             || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
1902     {
1903         /* GetDC on palettized formats is unsupported in D3D9, and the method is missing in
1904             D3D8, so this should only be used for DX <=7 surfaces (with non-device palettes) */
1905         unsigned int n;
1906         const PALETTEENTRY *pal = NULL;
1907
1908         if(This->palette) {
1909             pal = This->palette->palents;
1910         } else {
1911             IWineD3DSurfaceImpl *dds_primary;
1912             IWineD3DSwapChainImpl *swapchain;
1913             swapchain = (IWineD3DSwapChainImpl *)This->resource.device->swapchains[0];
1914             dds_primary = (IWineD3DSurfaceImpl *)swapchain->frontBuffer;
1915             if (dds_primary && dds_primary->palette)
1916                 pal = dds_primary->palette->palents;
1917         }
1918
1919         if (pal) {
1920             for (n=0; n<256; n++) {
1921                 col[n].rgbRed   = pal[n].peRed;
1922                 col[n].rgbGreen = pal[n].peGreen;
1923                 col[n].rgbBlue  = pal[n].peBlue;
1924                 col[n].rgbReserved = 0;
1925             }
1926             SetDIBColorTable(This->hDC, 0, 256, col);
1927         }
1928     }
1929
1930     *pHDC = This->hDC;
1931     TRACE("returning %p\n",*pHDC);
1932     This->Flags |= SFLAG_DCINUSE;
1933
1934     return WINED3D_OK;
1935 }
1936
1937 static HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC)
1938 {
1939     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1940
1941     TRACE("(%p)->(%p)\n",This,hDC);
1942
1943     if (!(This->Flags & SFLAG_DCINUSE))
1944         return WINEDDERR_NODC;
1945
1946     if (This->hDC !=hDC) {
1947         WARN("Application tries to release an invalid DC(%p), surface dc is %p\n", hDC, This->hDC);
1948         return WINEDDERR_NODC;
1949     }
1950
1951     if((This->Flags & SFLAG_PBO) && This->resource.allocatedMemory) {
1952         /* Copy the contents of the DIB over to the PBO */
1953         memcpy(This->resource.allocatedMemory, This->dib.bitmap_data, This->dib.bitmap_size);
1954     }
1955
1956     /* we locked first, so unlock now */
1957     IWineD3DSurface_UnlockRect(iface);
1958
1959     This->Flags &= ~SFLAG_DCINUSE;
1960
1961     return WINED3D_OK;
1962 }
1963
1964 /* ******************************************************
1965    IWineD3DSurface Internal (No mapping to directx api) parts follow
1966    ****************************************************** */
1967
1968 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp, BOOL srgb_mode) {
1969     BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
1970     const struct GlPixelFormatDesc *glDesc = This->resource.format_desc;
1971     IWineD3DDeviceImpl *device = This->resource.device;
1972     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
1973
1974     /* Default values: From the surface */
1975     *format = glDesc->glFormat;
1976     *type = glDesc->glType;
1977     *convert = NO_CONVERSION;
1978     *target_bpp = glDesc->byte_count;
1979
1980     if(srgb_mode) {
1981         *internal = glDesc->glGammaInternal;
1982     }
1983     else if (This->resource.usage & WINED3DUSAGE_RENDERTARGET
1984             && surface_is_offscreen((IWineD3DSurface *) This))
1985     {
1986         *internal = glDesc->rtInternal;
1987     } else {
1988         *internal = glDesc->glInternal;
1989     }
1990
1991     /* Ok, now look if we have to do any conversion */
1992     switch(This->resource.format_desc->format)
1993     {
1994         case WINED3DFMT_P8_UINT:
1995             /* ****************
1996                 Paletted Texture
1997                 **************** */
1998
1999              /* Use conversion when the paletted texture extension OR fragment shaders are available. When either
2000              * of the two is available make sure texturing is requested as neither of the two works in
2001              * conjunction with calls like glDraw-/glReadPixels. Further also use conversion in case of color keying.
2002              * Paletted textures can be emulated using shaders but only do that for 2D purposes e.g. situations
2003              * in which the main render target uses p8. Some games like GTA Vice City use P8 for texturing which
2004              * conflicts with this.
2005              */
2006             if (!(gl_info->supported[EXT_PALETTED_TEXTURE] || (device->blitter->color_fixup_supported(This->resource.format_desc->color_fixup)
2007                     && device->render_targets && This == (IWineD3DSurfaceImpl*)device->render_targets[0]))
2008                     || colorkey_active || !use_texturing)
2009             {
2010                 *format = GL_RGBA;
2011                 *internal = GL_RGBA;
2012                 *type = GL_UNSIGNED_BYTE;
2013                 *target_bpp = 4;
2014                 if(colorkey_active) {
2015                     *convert = CONVERT_PALETTED_CK;
2016                 } else {
2017                     *convert = CONVERT_PALETTED;
2018                 }
2019             }
2020             else if (!gl_info->supported[EXT_PALETTED_TEXTURE] && device->blitter->color_fixup_supported(This->resource.format_desc->color_fixup))
2021             {
2022                 *format = GL_ALPHA;
2023                 *type = GL_UNSIGNED_BYTE;
2024                 *target_bpp = 1;
2025             }
2026
2027             break;
2028
2029         case WINED3DFMT_B2G3R3_UNORM:
2030             /* **********************
2031                 GL_UNSIGNED_BYTE_3_3_2
2032                 ********************** */
2033             if (colorkey_active) {
2034                 /* This texture format will never be used.. So do not care about color keying
2035                     up until the point in time it will be needed :-) */
2036                 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
2037             }
2038             break;
2039
2040         case WINED3DFMT_B5G6R5_UNORM:
2041             if (colorkey_active) {
2042                 *convert = CONVERT_CK_565;
2043                 *format = GL_RGBA;
2044                 *internal = GL_RGB5_A1;
2045                 *type = GL_UNSIGNED_SHORT_5_5_5_1;
2046             }
2047             break;
2048
2049         case WINED3DFMT_B5G5R5X1_UNORM:
2050             if (colorkey_active) {
2051                 *convert = CONVERT_CK_5551;
2052                 *format = GL_BGRA;
2053                 *internal = GL_RGB5_A1;
2054                 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
2055             }
2056             break;
2057
2058         case WINED3DFMT_B8G8R8_UNORM:
2059             if (colorkey_active) {
2060                 *convert = CONVERT_CK_RGB24;
2061                 *format = GL_RGBA;
2062                 *internal = GL_RGBA8;
2063                 *type = GL_UNSIGNED_INT_8_8_8_8;
2064                 *target_bpp = 4;
2065             }
2066             break;
2067
2068         case WINED3DFMT_B8G8R8X8_UNORM:
2069             if (colorkey_active) {
2070                 *convert = CONVERT_RGB32_888;
2071                 *format = GL_RGBA;
2072                 *internal = GL_RGBA8;
2073                 *type = GL_UNSIGNED_INT_8_8_8_8;
2074             }
2075             break;
2076
2077         case WINED3DFMT_R8G8_SNORM:
2078             if (gl_info->supported[NV_TEXTURE_SHADER]) break;
2079             *convert = CONVERT_V8U8;
2080             *format = GL_BGR;
2081             *type = GL_UNSIGNED_BYTE;
2082             *target_bpp = 3;
2083             break;
2084
2085         case WINED3DFMT_R5G5_SNORM_L6_UNORM:
2086             *convert = CONVERT_L6V5U5;
2087             if (gl_info->supported[NV_TEXTURE_SHADER])
2088             {
2089                 *target_bpp = 3;
2090                 /* Use format and types from table */
2091             } else {
2092                 /* Load it into unsigned R5G6B5, swap L and V channels, and revert that in the shader */
2093                 *target_bpp = 2;
2094                 *format = GL_RGB;
2095                 *type = GL_UNSIGNED_SHORT_5_6_5;
2096             }
2097             break;
2098
2099         case WINED3DFMT_R8G8_SNORM_L8X8_UNORM:
2100             *convert = CONVERT_X8L8V8U8;
2101             *target_bpp = 4;
2102             if (gl_info->supported[NV_TEXTURE_SHADER])
2103             {
2104                 /* Use formats from gl table. It is a bit unfortunate, but the conversion
2105                  * is needed to set the X format to 255 to get 1.0 for alpha when sampling
2106                  * the texture. OpenGL can't use GL_DSDT8_MAG8_NV as internal format with
2107                  * the needed type and format parameter, so the internal format contains a
2108                  * 4th component, which is returned as alpha
2109                  */
2110             } else {
2111                 *format = GL_BGRA;
2112                 *type = GL_UNSIGNED_INT_8_8_8_8_REV;
2113             }
2114             break;
2115
2116         case WINED3DFMT_R8G8B8A8_SNORM:
2117             if (gl_info->supported[NV_TEXTURE_SHADER]) break;
2118             *convert = CONVERT_Q8W8V8U8;
2119             *format = GL_BGRA;
2120             *type = GL_UNSIGNED_BYTE;
2121             *target_bpp = 4;
2122             break;
2123
2124         case WINED3DFMT_R16G16_SNORM:
2125             if (gl_info->supported[NV_TEXTURE_SHADER]) break;
2126             *convert = CONVERT_V16U16;
2127             *format = GL_BGR;
2128             *type = GL_UNSIGNED_SHORT;
2129             *target_bpp = 6;
2130             break;
2131
2132         case WINED3DFMT_L4A4_UNORM:
2133             /* WINED3DFMT_L4A4_UNORM exists as an internal gl format, but for some reason there is not
2134              * format+type combination to load it. Thus convert it to A8L8, then load it
2135              * with A4L4 internal, but A8L8 format+type
2136              */
2137             *convert = CONVERT_A4L4;
2138             *format = GL_LUMINANCE_ALPHA;
2139             *type = GL_UNSIGNED_BYTE;
2140             *target_bpp = 2;
2141             break;
2142
2143         case WINED3DFMT_R16G16_UNORM:
2144             *convert = CONVERT_G16R16;
2145             *format = GL_RGB;
2146             *type = GL_UNSIGNED_SHORT;
2147             *target_bpp = 6;
2148             break;
2149
2150         case WINED3DFMT_R16G16_FLOAT:
2151             *convert = CONVERT_R16G16F;
2152             *format = GL_RGB;
2153             *type = GL_HALF_FLOAT_ARB;
2154             *target_bpp = 6;
2155             break;
2156
2157         case WINED3DFMT_R32G32_FLOAT:
2158             *convert = CONVERT_R32G32F;
2159             *format = GL_RGB;
2160             *type = GL_FLOAT;
2161             *target_bpp = 12;
2162             break;
2163
2164         case WINED3DFMT_S1_UINT_D15_UNORM:
2165             if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
2166                     || gl_info->supported[EXT_PACKED_DEPTH_STENCIL])
2167             {
2168                 *convert = CONVERT_D15S1;
2169                 *target_bpp = 4;
2170             }
2171             break;
2172
2173         case WINED3DFMT_S4X4_UINT_D24_UNORM:
2174             if (gl_info->supported[ARB_FRAMEBUFFER_OBJECT]
2175                     || gl_info->supported[EXT_PACKED_DEPTH_STENCIL])
2176             {
2177                 *convert = CONVERT_D24X4S4;
2178             }
2179             break;
2180
2181         case WINED3DFMT_S8_UINT_D24_FLOAT:
2182             if (gl_info->supported[ARB_DEPTH_BUFFER_FLOAT])
2183             {
2184                 *convert = CONVERT_D24FS8;
2185                 *target_bpp = 8;
2186             }
2187             break;
2188
2189         default:
2190             break;
2191     }
2192
2193     return WINED3D_OK;
2194 }
2195
2196 static void d3dfmt_p8_init_palette(IWineD3DSurfaceImpl *This, BYTE table[256][4], BOOL colorkey)
2197 {
2198     IWineD3DDeviceImpl *device = This->resource.device;
2199     IWineD3DPaletteImpl *pal = This->palette;
2200     BOOL index_in_alpha = FALSE;
2201     unsigned int i;
2202
2203     /* Old games like StarCraft, C&C, Red Alert and others use P8 render targets.
2204      * Reading back the RGB output each lockrect (each frame as they lock the whole screen)
2205      * is slow. Further RGB->P8 conversion is not possible because palettes can have
2206      * duplicate entries. Store the color key in the unused alpha component to speed the
2207      * download up and to make conversion unneeded. */
2208     index_in_alpha = primary_render_target_is_p8(device);
2209
2210     if (!pal)
2211     {
2212         UINT dxVersion = ((IWineD3DImpl *)device->wined3d)->dxVersion;
2213
2214         /* In DirectDraw the palette is a property of the surface, there are no such things as device palettes. */
2215         if (dxVersion <= 7)
2216         {
2217             ERR("This code should never get entered for DirectDraw!, expect problems\n");
2218             if (index_in_alpha)
2219             {
2220                 /* Guarantees that memory representation remains correct after sysmem<->texture transfers even if
2221                  * there's no palette at this time. */
2222                 for (i = 0; i < 256; i++) table[i][3] = i;
2223             }
2224         }
2225         else
2226         {
2227             /* Direct3D >= 8 palette usage style: P8 textures use device palettes, palette entry format is A8R8G8B8,
2228              * alpha is stored in peFlags and may be used by the app if D3DPTEXTURECAPS_ALPHAPALETTE device
2229              * capability flag is present (wine does advertise this capability) */
2230             for (i = 0; i < 256; ++i)
2231             {
2232                 table[i][0] = device->palettes[device->currentPalette][i].peRed;
2233                 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
2234                 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
2235                 table[i][3] = device->palettes[device->currentPalette][i].peFlags;
2236             }
2237         }
2238     }
2239     else
2240     {
2241         TRACE("Using surface palette %p\n", pal);
2242         /* Get the surface's palette */
2243         for (i = 0; i < 256; ++i)
2244         {
2245             table[i][0] = pal->palents[i].peRed;
2246             table[i][1] = pal->palents[i].peGreen;
2247             table[i][2] = pal->palents[i].peBlue;
2248
2249             /* When index_in_alpha is set the palette index is stored in the
2250              * alpha component. In case of a readback we can then read
2251              * GL_ALPHA. Color keying is handled in BltOverride using a
2252              * GL_ALPHA_TEST using GL_NOT_EQUAL. In case of index_in_alpha the
2253              * color key itself is passed to glAlphaFunc in other cases the
2254              * alpha component of pixels that should be masked away is set to 0. */
2255             if (index_in_alpha)
2256             {
2257                 table[i][3] = i;
2258             }
2259             else if (colorkey && (i >= This->SrcBltCKey.dwColorSpaceLowValue)
2260                     && (i <= This->SrcBltCKey.dwColorSpaceHighValue))
2261             {
2262                 table[i][3] = 0x00;
2263             }
2264             else if(pal->Flags & WINEDDPCAPS_ALPHA)
2265             {
2266                 table[i][3] = pal->palents[i].peFlags;
2267             }
2268             else
2269             {
2270                 table[i][3] = 0xFF;
2271             }
2272         }
2273     }
2274 }
2275
2276 static HRESULT d3dfmt_convert_surface(const BYTE *src, BYTE *dst, UINT pitch, UINT width,
2277         UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *This)
2278 {
2279     IWineD3DDeviceImpl *device = This->resource.device;
2280     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2281     const BYTE *source;
2282     BYTE *dest;
2283     TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert,This);
2284
2285     switch (convert) {
2286         case NO_CONVERSION:
2287         {
2288             memcpy(dst, src, pitch * height);
2289             break;
2290         }
2291         case CONVERT_PALETTED:
2292         case CONVERT_PALETTED_CK:
2293         {
2294             IWineD3DPaletteImpl* pal = This->palette;
2295             BYTE table[256][4];
2296             unsigned int x, y;
2297
2298             if( pal == NULL) {
2299                 /* TODO: If we are a sublevel, try to get the palette from level 0 */
2300             }
2301
2302             d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
2303
2304             for (y = 0; y < height; y++)
2305             {
2306                 source = src + pitch * y;
2307                 dest = dst + outpitch * y;
2308                 /* This is an 1 bpp format, using the width here is fine */
2309                 for (x = 0; x < width; x++) {
2310                     BYTE color = *source++;
2311                     *dest++ = table[color][0];
2312                     *dest++ = table[color][1];
2313                     *dest++ = table[color][2];
2314                     *dest++ = table[color][3];
2315                 }
2316             }
2317         }
2318         break;
2319
2320         case CONVERT_CK_565:
2321         {
2322             /* Converting the 565 format in 5551 packed to emulate color-keying.
2323
2324               Note : in all these conversion, it would be best to average the averaging
2325                       pixels to get the color of the pixel that will be color-keyed to
2326                       prevent 'color bleeding'. This will be done later on if ever it is
2327                       too visible.
2328
2329               Note2: Nvidia documents say that their driver does not support alpha + color keying
2330                      on the same surface and disables color keying in such a case
2331             */
2332             unsigned int x, y;
2333             const WORD *Source;
2334             WORD *Dest;
2335
2336             TRACE("Color keyed 565\n");
2337
2338             for (y = 0; y < height; y++) {
2339                 Source = (const WORD *)(src + y * pitch);
2340                 Dest = (WORD *) (dst + y * outpitch);
2341                 for (x = 0; x < width; x++ ) {
2342                     WORD color = *Source++;
2343                     *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
2344                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2345                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2346                         *Dest |= 0x0001;
2347                     }
2348                     Dest++;
2349                 }
2350             }
2351         }
2352         break;
2353
2354         case CONVERT_CK_5551:
2355         {
2356             /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
2357             unsigned int x, y;
2358             const WORD *Source;
2359             WORD *Dest;
2360             TRACE("Color keyed 5551\n");
2361             for (y = 0; y < height; y++) {
2362                 Source = (const WORD *)(src + y * pitch);
2363                 Dest = (WORD *) (dst + y * outpitch);
2364                 for (x = 0; x < width; x++ ) {
2365                     WORD color = *Source++;
2366                     *Dest = color;
2367                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2368                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2369                         *Dest |= (1 << 15);
2370                     }
2371                     else {
2372                         *Dest &= ~(1 << 15);
2373                     }
2374                     Dest++;
2375                 }
2376             }
2377         }
2378         break;
2379
2380         case CONVERT_CK_RGB24:
2381         {
2382             /* Converting R8G8B8 format to R8G8B8A8 with color-keying. */
2383             unsigned int x, y;
2384             for (y = 0; y < height; y++)
2385             {
2386                 source = src + pitch * y;
2387                 dest = dst + outpitch * y;
2388                 for (x = 0; x < width; x++) {
2389                     DWORD color = ((DWORD)source[0] << 16) + ((DWORD)source[1] << 8) + (DWORD)source[2] ;
2390                     DWORD dstcolor = color << 8;
2391                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2392                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2393                         dstcolor |= 0xff;
2394                     }
2395                     *(DWORD*)dest = dstcolor;
2396                     source += 3;
2397                     dest += 4;
2398                 }
2399             }
2400         }
2401         break;
2402
2403         case CONVERT_RGB32_888:
2404         {
2405             /* Converting X8R8G8B8 format to R8G8B8A8 with color-keying. */
2406             unsigned int x, y;
2407             for (y = 0; y < height; y++)
2408             {
2409                 source = src + pitch * y;
2410                 dest = dst + outpitch * y;
2411                 for (x = 0; x < width; x++) {
2412                     DWORD color = 0xffffff & *(const DWORD*)source;
2413                     DWORD dstcolor = color << 8;
2414                     if ((color < This->SrcBltCKey.dwColorSpaceLowValue) ||
2415                         (color > This->SrcBltCKey.dwColorSpaceHighValue)) {
2416                         dstcolor |= 0xff;
2417                     }
2418                     *(DWORD*)dest = dstcolor;
2419                     source += 4;
2420                     dest += 4;
2421                 }
2422             }
2423         }
2424         break;
2425
2426         case CONVERT_V8U8:
2427         {
2428             unsigned int x, y;
2429             const short *Source;
2430             unsigned char *Dest;
2431             for(y = 0; y < height; y++) {
2432                 Source = (const short *)(src + y * pitch);
2433                 Dest = dst + y * outpitch;
2434                 for (x = 0; x < width; x++ ) {
2435                     long color = (*Source++);
2436                     /* B */ Dest[0] = 0xff;
2437                     /* G */ Dest[1] = (color >> 8) + 128; /* V */
2438                     /* R */ Dest[2] = (color) + 128;      /* U */
2439                     Dest += 3;
2440                 }
2441             }
2442             break;
2443         }
2444
2445         case CONVERT_V16U16:
2446         {
2447             unsigned int x, y;
2448             const DWORD *Source;
2449             unsigned short *Dest;
2450             for(y = 0; y < height; y++) {
2451                 Source = (const DWORD *)(src + y * pitch);
2452                 Dest = (unsigned short *) (dst + y * outpitch);
2453                 for (x = 0; x < width; x++ ) {
2454                     DWORD color = (*Source++);
2455                     /* B */ Dest[0] = 0xffff;
2456                     /* G */ Dest[1] = (color >> 16) + 32768; /* V */
2457                     /* R */ Dest[2] = (color      ) + 32768; /* U */
2458                     Dest += 3;
2459                 }
2460             }
2461             break;
2462         }
2463
2464         case CONVERT_Q8W8V8U8:
2465         {
2466             unsigned int x, y;
2467             const DWORD *Source;
2468             unsigned char *Dest;
2469             for(y = 0; y < height; y++) {
2470                 Source = (const DWORD *)(src + y * pitch);
2471                 Dest = dst + y * outpitch;
2472                 for (x = 0; x < width; x++ ) {
2473                     long color = (*Source++);
2474                     /* B */ Dest[0] = ((color >> 16) & 0xff) + 128; /* W */
2475                     /* G */ Dest[1] = ((color >> 8 ) & 0xff) + 128; /* V */
2476                     /* R */ Dest[2] = (color         & 0xff) + 128; /* U */
2477                     /* A */ Dest[3] = ((color >> 24) & 0xff) + 128; /* Q */
2478                     Dest += 4;
2479                 }
2480             }
2481             break;
2482         }
2483
2484         case CONVERT_L6V5U5:
2485         {
2486             unsigned int x, y;
2487             const WORD *Source;
2488             unsigned char *Dest;
2489
2490             if (gl_info->supported[NV_TEXTURE_SHADER])
2491             {
2492                 /* This makes the gl surface bigger(24 bit instead of 16), but it works with
2493                  * fixed function and shaders without further conversion once the surface is
2494                  * loaded
2495                  */
2496                 for(y = 0; y < height; y++) {
2497                     Source = (const WORD *)(src + y * pitch);
2498                     Dest = dst + y * outpitch;
2499                     for (x = 0; x < width; x++ ) {
2500                         short color = (*Source++);
2501                         unsigned char l = ((color >> 10) & 0xfc);
2502                                   char v = ((color >>  5) & 0x3e);
2503                                   char u = ((color      ) & 0x1f);
2504
2505                         /* 8 bits destination, 6 bits source, 8th bit is the sign. gl ignores the sign
2506                          * and doubles the positive range. Thus shift left only once, gl does the 2nd
2507                          * shift. GL reads a signed value and converts it into an unsigned value.
2508                          */
2509                         /* M */ Dest[2] = l << 1;
2510
2511                         /* Those are read as signed, but kept signed. Just left-shift 3 times to scale
2512                          * from 5 bit values to 8 bit values.
2513                          */
2514                         /* V */ Dest[1] = v << 3;
2515                         /* U */ Dest[0] = u << 3;
2516                         Dest += 3;
2517                     }
2518                 }
2519             } else {
2520                 for(y = 0; y < height; y++) {
2521                     unsigned short *Dest_s = (unsigned short *) (dst + y * outpitch);
2522                     Source = (const WORD *)(src + y * pitch);
2523                     for (x = 0; x < width; x++ ) {
2524                         short color = (*Source++);
2525                         unsigned char l = ((color >> 10) & 0xfc);
2526                                  short v = ((color >>  5) & 0x3e);
2527                                  short u = ((color      ) & 0x1f);
2528                         short v_conv = v + 16;
2529                         short u_conv = u + 16;
2530
2531                         *Dest_s = ((v_conv << 11) & 0xf800) | ((l << 5) & 0x7e0) | (u_conv & 0x1f);
2532                         Dest_s += 1;
2533                     }
2534                 }
2535             }
2536             break;
2537         }
2538
2539         case CONVERT_X8L8V8U8:
2540         {
2541             unsigned int x, y;
2542             const DWORD *Source;
2543             unsigned char *Dest;
2544
2545             if (gl_info->supported[NV_TEXTURE_SHADER])
2546             {
2547                 /* This implementation works with the fixed function pipeline and shaders
2548                  * without further modification after converting the surface.
2549                  */
2550                 for(y = 0; y < height; y++) {
2551                     Source = (const DWORD *)(src + y * pitch);
2552                     Dest = dst + y * outpitch;
2553                     for (x = 0; x < width; x++ ) {
2554                         long color = (*Source++);
2555                         /* L */ Dest[2] = ((color >> 16) & 0xff);   /* L */
2556                         /* V */ Dest[1] = ((color >> 8 ) & 0xff);   /* V */
2557                         /* U */ Dest[0] = (color         & 0xff);   /* U */
2558                         /* I */ Dest[3] = 255;                      /* X */
2559                         Dest += 4;
2560                     }
2561                 }
2562             } else {
2563                 /* Doesn't work correctly with the fixed function pipeline, but can work in
2564                  * shaders if the shader is adjusted. (There's no use for this format in gl's
2565                  * standard fixed function pipeline anyway).
2566                  */
2567                 for(y = 0; y < height; y++) {
2568                     Source = (const DWORD *)(src + y * pitch);
2569                     Dest = dst + y * outpitch;
2570                     for (x = 0; x < width; x++ ) {
2571                         long color = (*Source++);
2572                         /* B */ Dest[0] = ((color >> 16) & 0xff);       /* L */
2573                         /* G */ Dest[1] = ((color >> 8 ) & 0xff) + 128; /* V */
2574                         /* R */ Dest[2] = (color         & 0xff) + 128;  /* U */
2575                         Dest += 4;
2576                     }
2577                 }
2578             }
2579             break;
2580         }
2581
2582         case CONVERT_A4L4:
2583         {
2584             unsigned int x, y;
2585             const unsigned char *Source;
2586             unsigned char *Dest;
2587             for(y = 0; y < height; y++) {
2588                 Source = src + y * pitch;
2589                 Dest = dst + y * outpitch;
2590                 for (x = 0; x < width; x++ ) {
2591                     unsigned char color = (*Source++);
2592                     /* A */ Dest[1] = (color & 0xf0) << 0;
2593                     /* L */ Dest[0] = (color & 0x0f) << 4;
2594                     Dest += 2;
2595                 }
2596             }
2597             break;
2598         }
2599
2600         case CONVERT_G16R16:
2601         case CONVERT_R16G16F:
2602         {
2603             unsigned int x, y;
2604             const WORD *Source;
2605             WORD *Dest;
2606
2607             for(y = 0; y < height; y++) {
2608                 Source = (const WORD *)(src + y * pitch);
2609                 Dest = (WORD *) (dst + y * outpitch);
2610                 for (x = 0; x < width; x++ ) {
2611                     WORD green = (*Source++);
2612                     WORD red = (*Source++);
2613                     Dest[0] = green;
2614                     Dest[1] = red;
2615                     /* Strictly speaking not correct for R16G16F, but it doesn't matter because the
2616                      * shader overwrites it anyway
2617                      */
2618                     Dest[2] = 0xffff;
2619                     Dest += 3;
2620                 }
2621             }
2622             break;
2623         }
2624
2625         case CONVERT_R32G32F:
2626         {
2627             unsigned int x, y;
2628             const float *Source;
2629             float *Dest;
2630             for(y = 0; y < height; y++) {
2631                 Source = (const float *)(src + y * pitch);
2632                 Dest = (float *) (dst + y * outpitch);
2633                 for (x = 0; x < width; x++ ) {
2634                     float green = (*Source++);
2635                     float red = (*Source++);
2636                     Dest[0] = green;
2637                     Dest[1] = red;
2638                     Dest[2] = 1.0f;
2639                     Dest += 3;
2640                 }
2641             }
2642             break;
2643         }
2644
2645         case CONVERT_D15S1:
2646         {
2647             unsigned int x, y;
2648
2649             for (y = 0; y < height; ++y)
2650             {
2651                 const WORD *source = (const WORD *)(src + y * pitch);
2652                 DWORD *dest = (DWORD *)(dst + y * outpitch);
2653
2654                 for (x = 0; x < width; ++x)
2655                 {
2656                     /* The depth data is normalized, so needs to be scaled,
2657                      * the stencil data isn't.  Scale depth data by
2658                      *      (2^24-1)/(2^15-1) ~~ (2^9 + 2^-6). */
2659                     WORD d15 = source[x] >> 1;
2660                     DWORD d24 = (d15 << 9) + (d15 >> 6);
2661                     dest[x] = (d24 << 8) | (source[x] & 0x1);
2662                 }
2663             }
2664             break;
2665         }
2666
2667         case CONVERT_D24X4S4:
2668         {
2669             unsigned int x, y;
2670
2671             for (y = 0; y < height; ++y)
2672             {
2673                 const DWORD *source = (const DWORD *)(src + y * pitch);
2674                 DWORD *dest = (DWORD *)(dst + y * outpitch);
2675
2676                 for (x = 0; x < width; ++x)
2677                 {
2678                     /* Just need to clear out the X4 part. */
2679                     dest[x] = source[x] & ~0xf0;
2680                 }
2681             }
2682             break;
2683         }
2684
2685         case CONVERT_D24FS8:
2686         {
2687             unsigned int x, y;
2688
2689             for (y = 0; y < height; ++y)
2690             {
2691                 const DWORD *source = (const DWORD *)(src + y * pitch);
2692                 float *dest_f = (float *)(dst + y * outpitch);
2693                 DWORD *dest_s = (DWORD *)(dst + y * outpitch);
2694
2695                 for (x = 0; x < width; ++x)
2696                 {
2697                     dest_f[x * 2] = float_24_to_32((source[x] & 0xffffff00) >> 8);
2698                     dest_s[x * 2 + 1] = source[x] & 0xff;
2699                 }
2700             }
2701             break;
2702         }
2703
2704         default:
2705             ERR("Unsupported conversion type %#x.\n", convert);
2706     }
2707     return WINED3D_OK;
2708 }
2709
2710 /* This function is used in case of 8bit paletted textures to upload the palette.
2711    It supports GL_EXT_paletted_texture and GL_ARB_fragment_program, support for other
2712    extensions like ATI_fragment_shaders is possible.
2713 */
2714 /* Context activation is done by the caller. */
2715 static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
2716     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2717     BYTE table[256][4];
2718     IWineD3DDeviceImpl *device = This->resource.device;
2719     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
2720
2721     d3dfmt_p8_init_palette(This, table, (convert == CONVERT_PALETTED_CK));
2722
2723     /* Try to use the paletted texture extension */
2724     if (gl_info->supported[EXT_PALETTED_TEXTURE])
2725     {
2726         TRACE("Using GL_EXT_PALETTED_TEXTURE for 8-bit paletted texture support\n");
2727         ENTER_GL();
2728         GL_EXTCALL(glColorTableEXT(This->texture_target, GL_RGBA, 256, GL_RGBA, GL_UNSIGNED_BYTE, table));
2729         LEAVE_GL();
2730     }
2731     else
2732     {
2733         /* Let a fragment shader do the color conversion by uploading the palette to a 1D texture.
2734          * The 8bit pixel data will be used as an index in this palette texture to retrieve the final color. */
2735         TRACE("Using fragment shaders for emulating 8-bit paletted texture support\n");
2736
2737         device->blitter->set_shader((IWineD3DDevice *) device, This->resource.format_desc,
2738                 This->texture_target, This->pow2Width, This->pow2Height);
2739
2740         ENTER_GL();
2741         GL_EXTCALL(glActiveTextureARB(GL_TEXTURE1));
2742         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2743
2744         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2745         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); /* Make sure we have discrete color levels. */
2746         glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2747         glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, table); /* Upload the palette */
2748
2749         /* Switch back to unit 0 in which the 2D texture will be stored. */
2750         GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0));
2751
2752         /* Rebind the texture because it isn't bound anymore */
2753         glBindTexture(This->texture_target, This->texture_name);
2754         LEAVE_GL();
2755     }
2756 }
2757
2758 BOOL palette9_changed(IWineD3DSurfaceImpl *This)
2759 {
2760     IWineD3DDeviceImpl *device = This->resource.device;
2761
2762     if (This->palette || (This->resource.format_desc->format != WINED3DFMT_P8_UINT
2763             && This->resource.format_desc->format != WINED3DFMT_P8_UINT_A8_UNORM))
2764     {
2765         /* If a ddraw-style palette is attached assume no d3d9 palette change.
2766          * Also the palette isn't interesting if the surface format isn't P8 or A8P8
2767          */
2768         return FALSE;
2769     }
2770
2771     if (This->palette9)
2772     {
2773         if (!memcmp(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256))
2774         {
2775             return FALSE;
2776         }
2777     } else {
2778         This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2779     }
2780     memcpy(This->palette9, device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
2781     return TRUE;
2782 }
2783
2784 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) {
2785     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2786     DWORD flag = srgb_mode ? SFLAG_INSRGBTEX : SFLAG_INTEXTURE;
2787
2788     if (!(This->Flags & flag)) {
2789         TRACE("Reloading because surface is dirty\n");
2790     } else if(/* Reload: gl texture has ck, now no ckey is set OR */
2791               ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) ||
2792               /* Reload: vice versa  OR */
2793               ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & WINEDDSD_CKSRCBLT)) ||
2794               /* Also reload: Color key is active AND the color key has changed */
2795               ((This->CKeyFlags & WINEDDSD_CKSRCBLT) && (
2796                 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
2797                 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
2798         TRACE("Reloading because of color keying\n");
2799         /* To perform the color key conversion we need a sysmem copy of
2800          * the surface. Make sure we have it
2801          */
2802
2803         IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
2804         /* Make sure the texture is reloaded because of the color key change, this kills performance though :( */
2805         /* TODO: This is not necessarily needed with hw palettized texture support */
2806         IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
2807     } else {
2808         TRACE("surface is already in texture\n");
2809         return WINED3D_OK;
2810     }
2811
2812     /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
2813      *  These resources are not bound by device size or format restrictions. Because of this,
2814      *  these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
2815      *  However, these resources can always be created, locked, and copied.
2816      */
2817     if (This->resource.pool == WINED3DPOOL_SCRATCH )
2818     {
2819         FIXME("(%p) Operation not supported for scratch textures\n",This);
2820         return WINED3DERR_INVALIDCALL;
2821     }
2822
2823     IWineD3DSurface_LoadLocation(iface, flag, NULL /* no partial locking for textures yet */);
2824
2825 #if 0
2826     {
2827         static unsigned int gen = 0;
2828         char buffer[4096];
2829         ++gen;
2830         if ((gen % 10) == 0) {
2831             snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm",
2832                     This, This->texture_target, This->texture_level, gen);
2833             IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
2834         }
2835         /*
2836          * debugging crash code
2837          if (gen == 250) {
2838          void** test = NULL;
2839          *test = 0;
2840          }
2841          */
2842     }
2843 #endif
2844
2845     if (!(This->Flags & SFLAG_DONOTFREE)) {
2846         HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
2847         This->resource.allocatedMemory = NULL;
2848         This->resource.heapMemory = NULL;
2849         IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, FALSE);
2850     }
2851
2852     return WINED3D_OK;
2853 }
2854
2855 /* Context activation is done by the caller. */
2856 static void WINAPI IWineD3DSurfaceImpl_BindTexture(IWineD3DSurface *iface, BOOL srgb) {
2857     /* TODO: check for locks */
2858     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2859     IWineD3DBaseTexture *baseTexture = NULL;
2860
2861     TRACE("(%p)Checking to see if the container is a base texture\n", This);
2862     if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2863         TRACE("Passing to container\n");
2864         IWineD3DBaseTexture_BindTexture(baseTexture, srgb);
2865         IWineD3DBaseTexture_Release(baseTexture);
2866     }
2867     else
2868     {
2869         GLuint *name;
2870
2871         TRACE("(%p) : Binding surface\n", This);
2872
2873         name = srgb ? &This->texture_name_srgb : &This->texture_name;
2874
2875         ENTER_GL();
2876
2877         if (!This->texture_level)
2878         {
2879             if (!*name) {
2880                 glGenTextures(1, name);
2881                 checkGLcall("glGenTextures");
2882                 TRACE("Surface %p given name %d\n", This, *name);
2883
2884                 glBindTexture(This->texture_target, *name);
2885                 checkGLcall("glBindTexture");
2886                 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
2887                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)");
2888                 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
2889                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)");
2890                 glTexParameteri(This->texture_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
2891                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE)");
2892                 glTexParameteri(This->texture_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2893                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MIN_FILTER, GL_NEAREST)");
2894                 glTexParameteri(This->texture_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2895                 checkGLcall("glTexParameteri(dimension, GL_TEXTURE_MAG_FILTER, GL_NEAREST)");
2896             }
2897             /* This is where we should be reducing the amount of GLMemoryUsed */
2898         } else if (*name) {
2899             /* Mipmap surfaces should have a base texture container */
2900             ERR("Mipmap surface has a glTexture bound to it!\n");
2901         }
2902
2903         glBindTexture(This->texture_target, *name);
2904         checkGLcall("glBindTexture");
2905
2906         LEAVE_GL();
2907     }
2908 }
2909
2910 #include <errno.h>
2911 #include <stdio.h>
2912 static HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename)
2913 {
2914     FILE* f = NULL;
2915     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2916     char *allocatedMemory;
2917     const char *textureRow;
2918     IWineD3DSwapChain *swapChain = NULL;
2919     int width, height, i, y;
2920     GLuint tmpTexture = 0;
2921     DWORD color;
2922     /*FIXME:
2923     Textures may not be stored in ->allocatedgMemory and a GlTexture
2924     so we should lock the surface before saving a snapshot, or at least check that
2925     */
2926     /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
2927     by calling GetTexImage and in compressed form by calling
2928     GetCompressedTexImageARB.  Queried compressed images can be saved and
2929     later reused by calling CompressedTexImage[123]DARB.  Pre-compressed
2930     texture images do not need to be processed by the GL and should
2931     significantly improve texture loading performance relative to uncompressed
2932     images. */
2933
2934 /* Setup the width and height to be the internal texture width and height. */
2935     width  = This->pow2Width;
2936     height = This->pow2Height;
2937 /* check to see if we're a 'virtual' texture, e.g. we're not a pbuffer of texture, we're a back buffer*/
2938     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
2939
2940     if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) {
2941         /* if were not a real texture then read the back buffer into a real texture */
2942         /* we don't want to interfere with the back buffer so read the data into a temporary
2943          * texture and then save the data out of the temporary texture
2944          */
2945         GLint prevRead;
2946         ENTER_GL();
2947         TRACE("(%p) Reading render target into texture\n", This);
2948
2949         glGenTextures(1, &tmpTexture);
2950         glBindTexture(GL_TEXTURE_2D, tmpTexture);
2951
2952         glTexImage2D(GL_TEXTURE_2D,
2953                         0,
2954                         GL_RGBA,
2955                         width,
2956                         height,
2957                         0/*border*/,
2958                         GL_RGBA,
2959                         GL_UNSIGNED_INT_8_8_8_8_REV,
2960                         NULL);
2961
2962         glGetIntegerv(GL_READ_BUFFER, &prevRead);
2963         checkGLcall("glGetIntegerv");
2964         glReadBuffer(swapChain ? GL_BACK : This->resource.device->offscreenBuffer);
2965         checkGLcall("glReadBuffer");
2966         glCopyTexImage2D(GL_TEXTURE_2D,
2967                             0,
2968                             GL_RGBA,
2969                             0,
2970                             0,
2971                             width,
2972                             height,
2973                             0);
2974
2975         checkGLcall("glCopyTexImage2D");
2976         glReadBuffer(prevRead);
2977         LEAVE_GL();
2978
2979     } else { /* bind the real texture, and make sure it up to date */
2980         surface_internal_preload(iface, SRGB_RGB);
2981         surface_bind_and_dirtify(This, FALSE);
2982     }
2983     allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width  * height * 4);
2984     ENTER_GL();
2985     FIXME("Saving texture level %d width %d height %d\n", This->texture_level, width, height);
2986     glGetTexImage(GL_TEXTURE_2D, This->texture_level, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, allocatedMemory);
2987     checkGLcall("glGetTexImage");
2988     if (tmpTexture) {
2989         glBindTexture(GL_TEXTURE_2D, 0);
2990         glDeleteTextures(1, &tmpTexture);
2991     }
2992     LEAVE_GL();
2993
2994     f = fopen(filename, "w+");
2995     if (NULL == f) {
2996         ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2997         return WINED3DERR_INVALIDCALL;
2998     }
2999 /* Save the data out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha channel */
3000     TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format_desc->format));
3001 /* TGA header */
3002     fputc(0,f);
3003     fputc(0,f);
3004     fputc(2,f);
3005     fputc(0,f);
3006     fputc(0,f);
3007     fputc(0,f);
3008     fputc(0,f);
3009     fputc(0,f);
3010     fputc(0,f);
3011     fputc(0,f);
3012     fputc(0,f);
3013     fputc(0,f);
3014 /* short width*/
3015     fwrite(&width,2,1,f);
3016 /* short height */
3017     fwrite(&height,2,1,f);
3018 /* format rgba */
3019     fputc(0x20,f);
3020     fputc(0x28,f);
3021 /* raw data */
3022     /* if the data is upside down if we've fetched it from a back buffer, so it needs flipping again to make it the correct way up */
3023     if(swapChain)
3024         textureRow = allocatedMemory + (width * (height - 1) *4);
3025     else
3026         textureRow = allocatedMemory;
3027     for (y = 0 ; y < height; y++) {
3028         for (i = 0; i < width;  i++) {
3029             color = *((const DWORD*)textureRow);
3030             fputc((color >> 16) & 0xFF, f); /* B */
3031             fputc((color >>  8) & 0xFF, f); /* G */
3032             fputc((color >>  0) & 0xFF, f); /* R */
3033             fputc((color >> 24) & 0xFF, f); /* A */
3034             textureRow += 4;
3035         }
3036         /* take two rows of the pointer to the texture memory */
3037         if(swapChain)
3038             (textureRow-= width << 3);
3039
3040     }
3041     TRACE("Closing file\n");
3042     fclose(f);
3043
3044     if(swapChain) {
3045         IWineD3DSwapChain_Release(swapChain);
3046     }
3047     HeapFree(GetProcessHeap(), 0, allocatedMemory);
3048     return WINED3D_OK;
3049 }
3050
3051 static HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
3052     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3053     HRESULT hr;
3054
3055     TRACE("(%p) : Calling base function first\n", This);
3056     hr = IWineD3DBaseSurfaceImpl_SetFormat(iface, format);
3057     if(SUCCEEDED(hr)) {
3058         This->Flags &= ~(SFLAG_ALLOCATED | SFLAG_SRGBALLOCATED);
3059         TRACE("(%p) : glFormat %d, glFormatInternal %d, glType %d\n", This, This->resource.format_desc->glFormat,
3060                 This->resource.format_desc->glInternal, This->resource.format_desc->glType);
3061     }
3062     return hr;
3063 }
3064
3065 static HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
3066     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3067
3068     if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
3069         WARN("Surface is locked or the HDC is in use\n");
3070         return WINED3DERR_INVALIDCALL;
3071     }
3072
3073     if(Mem && Mem != This->resource.allocatedMemory) {
3074         void *release = NULL;
3075
3076         /* Do I have to copy the old surface content? */
3077         if(This->Flags & SFLAG_DIBSECTION) {
3078                 /* Release the DC. No need to hold the critical section for the update
3079                  * Thread because this thread runs only on front buffers, but this method
3080                  * fails for render targets in the check above.
3081                  */
3082                 SelectObject(This->hDC, This->dib.holdbitmap);
3083                 DeleteDC(This->hDC);
3084                 /* Release the DIB section */
3085                 DeleteObject(This->dib.DIBsection);
3086                 This->dib.bitmap_data = NULL;
3087                 This->resource.allocatedMemory = NULL;
3088                 This->hDC = NULL;
3089                 This->Flags &= ~SFLAG_DIBSECTION;
3090         } else if(!(This->Flags & SFLAG_USERPTR)) {
3091             release = This->resource.heapMemory;
3092             This->resource.heapMemory = NULL;
3093         }
3094         This->resource.allocatedMemory = Mem;
3095         This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
3096
3097         /* Now the surface memory is most up do date. Invalidate drawable and texture */
3098         IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
3099
3100         /* For client textures opengl has to be notified */
3101         if(This->Flags & SFLAG_CLIENT) {
3102             surface_release_client_storage(iface);
3103         }
3104
3105         /* Now free the old memory if any */
3106         HeapFree(GetProcessHeap(), 0, release);
3107     } else if(This->Flags & SFLAG_USERPTR) {
3108         /* LockRect and GetDC will re-create the dib section and allocated memory */
3109         This->resource.allocatedMemory = NULL;
3110         /* HeapMemory should be NULL already */
3111         if(This->resource.heapMemory != NULL) ERR("User pointer surface has heap memory allocated\n");
3112         This->Flags &= ~SFLAG_USERPTR;
3113
3114         if(This->Flags & SFLAG_CLIENT) {
3115             surface_release_client_storage(iface);
3116         }
3117     }
3118     return WINED3D_OK;
3119 }
3120
3121 void flip_surface(IWineD3DSurfaceImpl *front, IWineD3DSurfaceImpl *back) {
3122
3123     /* Flip the surface contents */
3124     /* Flip the DC */
3125     {
3126         HDC tmp;
3127         tmp = front->hDC;
3128         front->hDC = back->hDC;
3129         back->hDC = tmp;
3130     }
3131
3132     /* Flip the DIBsection */
3133     {
3134         HBITMAP tmp;
3135         BOOL hasDib = front->Flags & SFLAG_DIBSECTION;
3136         tmp = front->dib.DIBsection;
3137         front->dib.DIBsection = back->dib.DIBsection;
3138         back->dib.DIBsection = tmp;
3139
3140         if(back->Flags & SFLAG_DIBSECTION) front->Flags |= SFLAG_DIBSECTION;
3141         else front->Flags &= ~SFLAG_DIBSECTION;
3142         if(hasDib) back->Flags |= SFLAG_DIBSECTION;
3143         else back->Flags &= ~SFLAG_DIBSECTION;
3144     }
3145
3146     /* Flip the surface data */
3147     {
3148         void* tmp;
3149
3150         tmp = front->dib.bitmap_data;
3151         front->dib.bitmap_data = back->dib.bitmap_data;
3152         back->dib.bitmap_data = tmp;
3153
3154         tmp = front->resource.allocatedMemory;
3155         front->resource.allocatedMemory = back->resource.allocatedMemory;
3156         back->resource.allocatedMemory = tmp;
3157
3158         tmp = front->resource.heapMemory;
3159         front->resource.heapMemory = back->resource.heapMemory;
3160         back->resource.heapMemory = tmp;
3161     }
3162
3163     /* Flip the PBO */
3164     {
3165         GLuint tmp_pbo = front->pbo;
3166         front->pbo = back->pbo;
3167         back->pbo = tmp_pbo;
3168     }
3169
3170     /* client_memory should not be different, but just in case */
3171     {
3172         BOOL tmp;
3173         tmp = front->dib.client_memory;
3174         front->dib.client_memory = back->dib.client_memory;
3175         back->dib.client_memory = tmp;
3176     }
3177
3178     /* Flip the opengl texture */
3179     {
3180         GLuint tmp;
3181
3182         tmp = back->texture_name;
3183         back->texture_name = front->texture_name;
3184         front->texture_name = tmp;
3185
3186         tmp = back->texture_name_srgb;
3187         back->texture_name_srgb = front->texture_name_srgb;
3188         front->texture_name_srgb = tmp;
3189     }
3190
3191     {
3192         DWORD tmp_flags = back->Flags;
3193         back->Flags = front->Flags;
3194         front->Flags = tmp_flags;
3195     }
3196 }
3197
3198 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
3199     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3200     IWineD3DSwapChainImpl *swapchain = NULL;
3201     HRESULT hr;
3202     TRACE("(%p)->(%p,%x)\n", This, override, Flags);
3203
3204     /* Flipping is only supported on RenderTargets and overlays*/
3205     if( !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_OVERLAY)) ) {
3206         WARN("Tried to flip a non-render target, non-overlay surface\n");
3207         return WINEDDERR_NOTFLIPPABLE;
3208     }
3209
3210     if(This->resource.usage & WINED3DUSAGE_OVERLAY) {
3211         flip_surface(This, (IWineD3DSurfaceImpl *) override);
3212
3213         /* Update the overlay if it is visible */
3214         if(This->overlay_dest) {
3215             return IWineD3DSurface_DrawOverlay((IWineD3DSurface *) This);
3216         } else {
3217             return WINED3D_OK;
3218         }
3219     }
3220
3221     if(override) {
3222         /* DDraw sets this for the X11 surfaces, so don't confuse the user
3223          * FIXME("(%p) Target override is not supported by now\n", This);
3224          * Additionally, it isn't really possible to support triple-buffering
3225          * properly on opengl at all
3226          */
3227     }
3228
3229     IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain);
3230     if(!swapchain) {
3231         ERR("Flipped surface is not on a swapchain\n");
3232         return WINEDDERR_NOTFLIPPABLE;
3233     }
3234
3235     /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
3236      * and only d3d8 and d3d9 apps specify the presentation interval
3237      */
3238     if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) {
3239         /* Most common case first to avoid wasting time on all the other cases */
3240         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
3241     } else if(Flags & WINEDDFLIP_NOVSYNC) {
3242         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
3243     } else if(Flags & WINEDDFLIP_INTERVAL2) {
3244         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
3245     } else if(Flags & WINEDDFLIP_INTERVAL3) {
3246         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
3247     } else {
3248         swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
3249     }
3250
3251     /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
3252     hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *) swapchain, NULL, NULL, 0, NULL, 0);
3253     IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
3254     return hr;
3255 }
3256
3257 /* Does a direct frame buffer -> texture copy. Stretching is done
3258  * with single pixel copy calls
3259  */
3260 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface,
3261         const WINED3DRECT *srect, const WINED3DRECT *drect, BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter)
3262 {
3263     IWineD3DDeviceImpl *myDevice = This->resource.device;
3264     float xrel, yrel;
3265     UINT row;
3266     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3267     struct wined3d_context *context;
3268
3269
3270     context = context_acquire(myDevice, SrcSurface, CTXUSAGE_BLIT);
3271     surface_internal_preload((IWineD3DSurface *) This, SRGB_RGB);
3272     ENTER_GL();
3273
3274     /* Bind the target texture */
3275     glBindTexture(This->texture_target, This->texture_name);
3276     checkGLcall("glBindTexture");
3277     if(surface_is_offscreen(SrcSurface)) {
3278         TRACE("Reading from an offscreen target\n");
3279         upsidedown = !upsidedown;
3280         glReadBuffer(myDevice->offscreenBuffer);
3281     }
3282     else
3283     {
3284         glReadBuffer(surface_get_gl_buffer(SrcSurface));
3285     }
3286     checkGLcall("glReadBuffer");
3287
3288     xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
3289     yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
3290
3291     if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3292     {
3293         FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
3294
3295         if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
3296             ERR("Texture filtering not supported in direct blit\n");
3297         }
3298     }
3299     else if ((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT)
3300             && ((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3301     {
3302         ERR("Texture filtering not supported in direct blit\n");
3303     }
3304
3305     if (upsidedown
3306             && !((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3307             && !((yrel - 1.0f < -eps) || (yrel - 1.0f > eps)))
3308     {
3309         /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
3310
3311         glCopyTexSubImage2D(This->texture_target, This->texture_level,
3312                 drect->x1 /*xoffset */, drect->y1 /* y offset */,
3313                 srect->x1, Src->currentDesc.Height - srect->y2,
3314                 drect->x2 - drect->x1, drect->y2 - drect->y1);
3315     } else {
3316         UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
3317         /* I have to process this row by row to swap the image,
3318          * otherwise it would be upside down, so stretching in y direction
3319          * doesn't cost extra time
3320          *
3321          * However, stretching in x direction can be avoided if not necessary
3322          */
3323         for(row = drect->y1; row < drect->y2; row++) {
3324             if ((xrel - 1.0f < -eps) || (xrel - 1.0f > eps))
3325             {
3326                 /* Well, that stuff works, but it's very slow.
3327                  * find a better way instead
3328                  */
3329                 UINT col;
3330
3331                 for(col = drect->x1; col < drect->x2; col++) {
3332                     glCopyTexSubImage2D(This->texture_target, This->texture_level,
3333                             drect->x1 + col /* x offset */, row /* y offset */,
3334                             srect->x1 + col * xrel, yoffset - (int) (row * yrel), 1, 1);
3335                 }
3336             } else {
3337                 glCopyTexSubImage2D(This->texture_target, This->texture_level,
3338                         drect->x1 /* x offset */, row /* y offset */,
3339                         srect->x1, yoffset - (int) (row * yrel), drect->x2-drect->x1, 1);
3340             }
3341         }
3342     }
3343     checkGLcall("glCopyTexSubImage2D");
3344
3345     LEAVE_GL();
3346     context_release(context);
3347
3348     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3349      * path is never entered
3350      */
3351     IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INTEXTURE, TRUE);
3352 }
3353
3354 /* Uses the hardware to stretch and flip the image */
3355 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface,
3356         IWineD3DSwapChainImpl *swapchain, const WINED3DRECT *srect, const WINED3DRECT *drect,
3357         BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter)
3358 {
3359     IWineD3DDeviceImpl *myDevice = This->resource.device;
3360     GLuint src, backup = 0;
3361     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3362     float left, right, top, bottom; /* Texture coordinates */
3363     UINT fbwidth = Src->currentDesc.Width;
3364     UINT fbheight = Src->currentDesc.Height;
3365     struct wined3d_context *context;
3366     GLenum drawBuffer = GL_BACK;
3367     GLenum texture_target;
3368     BOOL noBackBufferBackup;
3369     BOOL src_offscreen;
3370
3371     TRACE("Using hwstretch blit\n");
3372     /* Activate the Proper context for reading from the source surface, set it up for blitting */
3373     context = context_acquire(myDevice, SrcSurface, CTXUSAGE_BLIT);
3374     surface_internal_preload((IWineD3DSurface *) This, SRGB_RGB);
3375
3376     src_offscreen = surface_is_offscreen(SrcSurface);
3377     noBackBufferBackup = src_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO;
3378     if (!noBackBufferBackup && !Src->texture_name)
3379     {
3380         /* Get it a description */
3381         surface_internal_preload(SrcSurface, SRGB_RGB);
3382     }
3383     ENTER_GL();
3384
3385     /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
3386      * This way we don't have to wait for the 2nd readback to finish to leave this function.
3387      */
3388     if (context->aux_buffers >= 2)
3389     {
3390         /* Got more than one aux buffer? Use the 2nd aux buffer */
3391         drawBuffer = GL_AUX1;
3392     }
3393     else if ((!src_offscreen || myDevice->offscreenBuffer == GL_BACK) && context->aux_buffers >= 1)
3394     {
3395         /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
3396         drawBuffer = GL_AUX0;
3397     }
3398
3399     if(noBackBufferBackup) {
3400         glGenTextures(1, &backup);
3401         checkGLcall("glGenTextures");
3402         glBindTexture(GL_TEXTURE_2D, backup);
3403         checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3404         texture_target = GL_TEXTURE_2D;
3405     } else {
3406         /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
3407          * we are reading from the back buffer, the backup can be used as source texture
3408          */
3409         texture_target = Src->texture_target;
3410         glBindTexture(texture_target, Src->texture_name);
3411         checkGLcall("glBindTexture(texture_target, Src->texture_name)");
3412         glEnable(texture_target);
3413         checkGLcall("glEnable(texture_target)");
3414
3415         /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
3416         Src->Flags &= ~SFLAG_INTEXTURE;
3417     }
3418
3419     if (src_offscreen)
3420     {
3421         TRACE("Reading from an offscreen target\n");
3422         upsidedown = !upsidedown;
3423         glReadBuffer(myDevice->offscreenBuffer);
3424     }
3425     else
3426     {
3427         glReadBuffer(surface_get_gl_buffer(SrcSurface));
3428     }
3429
3430     /* TODO: Only back up the part that will be overwritten */
3431     glCopyTexSubImage2D(texture_target, 0,
3432                         0, 0 /* read offsets */,
3433                         0, 0,
3434                         fbwidth,
3435                         fbheight);
3436
3437     checkGLcall("glCopyTexSubImage2D");
3438
3439     /* No issue with overriding these - the sampler is dirty due to blit usage */
3440     glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER,
3441             wined3d_gl_mag_filter(magLookup, Filter));
3442     checkGLcall("glTexParameteri");
3443     glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER,
3444             wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
3445     checkGLcall("glTexParameteri");
3446
3447     if(!swapchain || (IWineD3DSurface *) Src == swapchain->backBuffer[0]) {
3448         src = backup ? backup : Src->texture_name;
3449     } else {
3450         glReadBuffer(GL_FRONT);
3451         checkGLcall("glReadBuffer(GL_FRONT)");
3452
3453         glGenTextures(1, &src);
3454         checkGLcall("glGenTextures(1, &src)");
3455         glBindTexture(GL_TEXTURE_2D, src);
3456         checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
3457
3458         /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
3459          * out for power of 2 sizes
3460          */
3461         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
3462                     GL_RGBA, GL_UNSIGNED_BYTE, NULL);
3463         checkGLcall("glTexImage2D");
3464         glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
3465                             0, 0 /* read offsets */,
3466                             0, 0,
3467                             fbwidth,
3468                             fbheight);
3469
3470         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
3471         checkGLcall("glTexParameteri");
3472         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
3473         checkGLcall("glTexParameteri");
3474
3475         glReadBuffer(GL_BACK);
3476         checkGLcall("glReadBuffer(GL_BACK)");
3477
3478         if(texture_target != GL_TEXTURE_2D) {
3479             glDisable(texture_target);
3480             glEnable(GL_TEXTURE_2D);
3481             texture_target = GL_TEXTURE_2D;
3482         }
3483     }
3484     checkGLcall("glEnd and previous");
3485
3486     left = srect->x1;
3487     right = srect->x2;
3488
3489     if(upsidedown) {
3490         top = Src->currentDesc.Height - srect->y1;
3491         bottom = Src->currentDesc.Height - srect->y2;
3492     } else {
3493         top = Src->currentDesc.Height - srect->y2;
3494         bottom = Src->currentDesc.Height - srect->y1;
3495     }
3496
3497     if(Src->Flags & SFLAG_NORMCOORD) {
3498         left /= Src->pow2Width;
3499         right /= Src->pow2Width;
3500         top /= Src->pow2Height;
3501         bottom /= Src->pow2Height;
3502     }
3503
3504     /* draw the source texture stretched and upside down. The correct surface is bound already */
3505     glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
3506     glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
3507
3508     context_set_draw_buffer(context, drawBuffer);
3509     glReadBuffer(drawBuffer);
3510
3511     glBegin(GL_QUADS);
3512         /* bottom left */
3513         glTexCoord2f(left, bottom);
3514         glVertex2i(0, fbheight);
3515
3516         /* top left */
3517         glTexCoord2f(left, top);
3518         glVertex2i(0, fbheight - drect->y2 - drect->y1);
3519
3520         /* top right */
3521         glTexCoord2f(right, top);
3522         glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
3523
3524         /* bottom right */
3525         glTexCoord2f(right, bottom);
3526         glVertex2i(drect->x2 - drect->x1, fbheight);
3527     glEnd();
3528     checkGLcall("glEnd and previous");
3529
3530     if (texture_target != This->texture_target)
3531     {
3532         glDisable(texture_target);
3533         glEnable(This->texture_target);
3534         texture_target = This->texture_target;
3535     }
3536
3537     /* Now read the stretched and upside down image into the destination texture */
3538     glBindTexture(texture_target, This->texture_name);
3539     checkGLcall("glBindTexture");
3540     glCopyTexSubImage2D(texture_target,
3541                         0,
3542                         drect->x1, drect->y1, /* xoffset, yoffset */
3543                         0, 0, /* We blitted the image to the origin */
3544                         drect->x2 - drect->x1, drect->y2 - drect->y1);
3545     checkGLcall("glCopyTexSubImage2D");
3546
3547     if(drawBuffer == GL_BACK) {
3548         /* Write the back buffer backup back */
3549         if(backup) {
3550             if(texture_target != GL_TEXTURE_2D) {
3551                 glDisable(texture_target);
3552                 glEnable(GL_TEXTURE_2D);
3553                 texture_target = GL_TEXTURE_2D;
3554             }
3555             glBindTexture(GL_TEXTURE_2D, backup);
3556             checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
3557         } else {
3558             if (texture_target != Src->texture_target)
3559             {
3560                 glDisable(texture_target);
3561                 glEnable(Src->texture_target);
3562                 texture_target = Src->texture_target;
3563             }
3564             glBindTexture(Src->texture_target, Src->texture_name);
3565             checkGLcall("glBindTexture(Src->texture_target, Src->texture_name)");
3566         }
3567
3568         glBegin(GL_QUADS);
3569             /* top left */
3570             glTexCoord2f(0.0f, (float)fbheight / (float)Src->pow2Height);
3571             glVertex2i(0, 0);
3572
3573             /* bottom left */
3574             glTexCoord2f(0.0f, 0.0f);
3575             glVertex2i(0, fbheight);
3576
3577             /* bottom right */
3578             glTexCoord2f((float)fbwidth / (float)Src->pow2Width, 0.0f);
3579             glVertex2i(fbwidth, Src->currentDesc.Height);
3580
3581             /* top right */
3582             glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
3583             glVertex2i(fbwidth, 0);
3584         glEnd();
3585     }
3586     glDisable(texture_target);
3587     checkGLcall("glDisable(texture_target)");
3588
3589     /* Cleanup */
3590     if (src != Src->texture_name && src != backup)
3591     {
3592         glDeleteTextures(1, &src);
3593         checkGLcall("glDeleteTextures(1, &src)");
3594     }
3595     if(backup) {
3596         glDeleteTextures(1, &backup);
3597         checkGLcall("glDeleteTextures(1, &backup)");
3598     }
3599
3600     LEAVE_GL();
3601
3602     wglFlush(); /* Flush to ensure ordering across contexts. */
3603
3604     context_release(context);
3605
3606     /* The texture is now most up to date - If the surface is a render target and has a drawable, this
3607      * path is never entered
3608      */
3609     IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INTEXTURE, TRUE);
3610 }
3611
3612 /* Not called from the VTable */
3613 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, const RECT *DestRect,
3614         IWineD3DSurface *SrcSurface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx,
3615         WINED3DTEXTUREFILTERTYPE Filter)
3616 {
3617     IWineD3DDeviceImpl *myDevice = This->resource.device;
3618     WINED3DRECT rect;
3619     IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
3620     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3621
3622     TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
3623
3624     /* Get the swapchain. One of the surfaces has to be a primary surface */
3625     if(This->resource.pool == WINED3DPOOL_SYSTEMMEM) {
3626         WARN("Destination is in sysmem, rejecting gl blt\n");
3627         return WINED3DERR_INVALIDCALL;
3628     }
3629     IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
3630     if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
3631     if(Src) {
3632         if(Src->resource.pool == WINED3DPOOL_SYSTEMMEM) {
3633             WARN("Src is in sysmem, rejecting gl blt\n");
3634             return WINED3DERR_INVALIDCALL;
3635         }
3636         IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
3637         if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
3638     }
3639
3640     /* Early sort out of cases where no render target is used */
3641     if(!dstSwapchain && !srcSwapchain &&
3642         SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
3643         TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
3644         return WINED3DERR_INVALIDCALL;
3645     }
3646
3647     /* No destination color keying supported */
3648     if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) {
3649         /* Can we support that with glBlendFunc if blitting to the frame buffer? */
3650         TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
3651         return WINED3DERR_INVALIDCALL;
3652     }
3653
3654     if (DestRect) {
3655         rect.x1 = DestRect->left;
3656         rect.y1 = DestRect->top;
3657         rect.x2 = DestRect->right;
3658         rect.y2 = DestRect->bottom;
3659     } else {
3660         rect.x1 = 0;
3661         rect.y1 = 0;
3662         rect.x2 = This->currentDesc.Width;
3663         rect.y2 = This->currentDesc.Height;
3664     }
3665
3666     /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
3667     if(dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->backBuffer &&
3668        ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) && SrcSurface == dstSwapchain->backBuffer[0]) {
3669         /* Half-life does a Blt from the back buffer to the front buffer,
3670          * Full surface size, no flags... Use present instead
3671          *
3672          * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
3673          */
3674
3675         /* Check rects - IWineD3DDevice_Present doesn't handle them */
3676         while(1)
3677         {
3678             RECT mySrcRect;
3679             TRACE("Looking if a Present can be done...\n");
3680             /* Source Rectangle must be full surface */
3681             if( SrcRect ) {
3682                 if(SrcRect->left != 0 || SrcRect->top != 0 ||
3683                    SrcRect->right != Src->currentDesc.Width || SrcRect->bottom != Src->currentDesc.Height) {
3684                     TRACE("No, Source rectangle doesn't match\n");
3685                     break;
3686                 }
3687             }
3688             mySrcRect.left = 0;
3689             mySrcRect.top = 0;
3690             mySrcRect.right = Src->currentDesc.Width;
3691             mySrcRect.bottom = Src->currentDesc.Height;
3692
3693             /* No stretching may occur */
3694             if(mySrcRect.right != rect.x2 - rect.x1 ||
3695                mySrcRect.bottom != rect.y2 - rect.y1) {
3696                 TRACE("No, stretching is done\n");
3697                 break;
3698             }
3699
3700             /* Destination must be full surface or match the clipping rectangle */
3701             if(This->clipper && ((IWineD3DClipperImpl *) This->clipper)->hWnd)
3702             {
3703                 RECT cliprect;
3704                 POINT pos[2];
3705                 GetClientRect(((IWineD3DClipperImpl *) This->clipper)->hWnd, &cliprect);
3706                 pos[0].x = rect.x1;
3707                 pos[0].y = rect.y1;
3708                 pos[1].x = rect.x2;
3709                 pos[1].y = rect.y2;
3710                 MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl *) This->clipper)->hWnd,
3711                                 pos, 2);
3712
3713                 if(pos[0].x != cliprect.left  || pos[0].y != cliprect.top   ||
3714                    pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
3715                 {
3716                     TRACE("No, dest rectangle doesn't match(clipper)\n");
3717                     TRACE("Clip rect at (%d,%d)-(%d,%d)\n", cliprect.left, cliprect.top, cliprect.right, cliprect.bottom);
3718                     TRACE("Blt dest: (%d,%d)-(%d,%d)\n", rect.x1, rect.y1, rect.x2, rect.y2);
3719                     break;
3720                 }
3721             }
3722             else
3723             {
3724                 if(rect.x1 != 0 || rect.y1 != 0 ||
3725                    rect.x2 != This->currentDesc.Width || rect.y2 != This->currentDesc.Height) {
3726                     TRACE("No, dest rectangle doesn't match(surface size)\n");
3727                     break;
3728                 }
3729             }
3730
3731             TRACE("Yes\n");
3732
3733             /* These flags are unimportant for the flag check, remove them */
3734             if((Flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)) == 0) {
3735                 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
3736
3737                 /* The idea behind this is that a glReadPixels and a glDrawPixels call
3738                     * take very long, while a flip is fast.
3739                     * This applies to Half-Life, which does such Blts every time it finished
3740                     * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
3741                     * menu. This is also used by all apps when they do windowed rendering
3742                     *
3743                     * The problem is that flipping is not really the same as copying. After a
3744                     * Blt the front buffer is a copy of the back buffer, and the back buffer is
3745                     * untouched. Therefore it's necessary to override the swap effect
3746                     * and to set it back after the flip.
3747                     *
3748                     * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
3749                     * testcases.
3750                     */
3751
3752                 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
3753                 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
3754
3755                 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
3756                 IWineD3DSwapChain_Present((IWineD3DSwapChain *) dstSwapchain, NULL, NULL, 0, NULL, 0);
3757
3758                 dstSwapchain->presentParms.SwapEffect = orig_swap;
3759
3760                 return WINED3D_OK;
3761             }
3762             break;
3763         }
3764
3765         TRACE("Unsupported blit between buffers on the same swapchain\n");
3766         return WINED3DERR_INVALIDCALL;
3767     } else if(dstSwapchain && dstSwapchain == srcSwapchain) {
3768         FIXME("Implement hardware blit between two surfaces on the same swapchain\n");
3769         return WINED3DERR_INVALIDCALL;
3770     } else if(dstSwapchain && srcSwapchain) {
3771         FIXME("Implement hardware blit between two different swapchains\n");
3772         return WINED3DERR_INVALIDCALL;
3773     } else if(dstSwapchain) {
3774         if(SrcSurface == myDevice->render_targets[0]) {
3775             TRACE("Blit from active render target to a swapchain\n");
3776             /* Handled with regular texture -> swapchain blit */
3777         }
3778     } else if(srcSwapchain && This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
3779         FIXME("Implement blit from a swapchain to the active render target\n");
3780         return WINED3DERR_INVALIDCALL;
3781     }
3782
3783     if((srcSwapchain || SrcSurface == myDevice->render_targets[0]) && !dstSwapchain) {
3784         /* Blit from render target to texture */
3785         WINED3DRECT srect;
3786         BOOL upsideDown, stretchx;
3787         BOOL paletteOverride = FALSE;
3788
3789         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3790             TRACE("Color keying not supported by frame buffer to texture blit\n");
3791             return WINED3DERR_INVALIDCALL;
3792             /* Destination color key is checked above */
3793         }
3794
3795         /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
3796          * glCopyTexSubImage is a bit picky about the parameters we pass to it
3797          */
3798         if(SrcRect) {
3799             if(SrcRect->top < SrcRect->bottom) {
3800                 srect.y1 = SrcRect->top;
3801                 srect.y2 = SrcRect->bottom;
3802                 upsideDown = FALSE;
3803             } else {
3804                 srect.y1 = SrcRect->bottom;
3805                 srect.y2 = SrcRect->top;
3806                 upsideDown = TRUE;
3807             }
3808             srect.x1 = SrcRect->left;
3809             srect.x2 = SrcRect->right;
3810         } else {
3811             srect.x1 = 0;
3812             srect.y1 = 0;
3813             srect.x2 = Src->currentDesc.Width;
3814             srect.y2 = Src->currentDesc.Height;
3815             upsideDown = FALSE;
3816         }
3817         if(rect.x1 > rect.x2) {
3818             UINT tmp = rect.x2;
3819             rect.x2 = rect.x1;
3820             rect.x1 = tmp;
3821             upsideDown = !upsideDown;
3822         }
3823
3824         if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
3825             stretchx = TRUE;
3826         } else {
3827             stretchx = FALSE;
3828         }
3829
3830         /* When blitting from a render target a texture, the texture isn't required to have a palette.
3831          * In this case grab the palette from the render target. */
3832         if (This->resource.format_desc->format == WINED3DFMT_P8_UINT && !This->palette)
3833         {
3834             paletteOverride = TRUE;
3835             TRACE("Source surface (%p) lacks palette, overriding palette with palette %p of destination surface (%p)\n", Src, This->palette, This);
3836             This->palette = Src->palette;
3837         }
3838
3839         /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
3840          * flip the image nor scale it.
3841          *
3842          * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
3843          * -> If the app wants a image width an unscaled width, copy it line per line
3844          * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
3845          *    than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
3846          *    back buffer. This is slower than reading line per line, thus not used for flipping
3847          * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
3848          *    pixel by pixel
3849          *
3850          * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
3851          * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
3852          * backends.
3853          */
3854         if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
3855                 && myDevice->adapter->gl_info.fbo_ops.glBlitFramebuffer
3856                 && surface_can_stretch_rect(Src, This))
3857         {
3858             stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &srect,
3859                     (IWineD3DSurface *)This, &rect, Filter, upsideDown);
3860         } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
3861                                     rect.y2 - rect.y1 > Src->currentDesc.Height) {
3862             TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
3863             fb_copy_to_texture_direct(This, SrcSurface, &srect, &rect, upsideDown, Filter);
3864         } else {
3865             TRACE("Using hardware stretching to flip / stretch the texture\n");
3866             fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown, Filter);
3867         }
3868
3869         /* Clear the palette as the surface didn't have a palette attached, it would confuse GetPalette and other calls */
3870         if(paletteOverride)
3871             This->palette = NULL;
3872
3873         if(!(This->Flags & SFLAG_DONOTFREE)) {
3874             HeapFree(GetProcessHeap(), 0, This->resource.heapMemory);
3875             This->resource.allocatedMemory = NULL;
3876             This->resource.heapMemory = NULL;
3877         } else {
3878             This->Flags &= ~SFLAG_INSYSMEM;
3879         }
3880
3881         return WINED3D_OK;
3882     } else if(Src) {
3883         /* Blit from offscreen surface to render target */
3884         float glTexCoord[4];
3885         DWORD oldCKeyFlags = Src->CKeyFlags;
3886         WINEDDCOLORKEY oldBltCKey = Src->SrcBltCKey;
3887         struct wined3d_context *context;
3888         RECT SourceRectangle;
3889         BOOL paletteOverride = FALSE;
3890
3891         TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
3892
3893         if(SrcRect) {
3894             SourceRectangle.left = SrcRect->left;
3895             SourceRectangle.right = SrcRect->right;
3896             SourceRectangle.top = SrcRect->top;
3897             SourceRectangle.bottom = SrcRect->bottom;
3898         } else {
3899             SourceRectangle.left = 0;
3900             SourceRectangle.right = Src->currentDesc.Width;
3901             SourceRectangle.top = 0;
3902             SourceRectangle.bottom = Src->currentDesc.Height;
3903         }
3904
3905         /* When blitting from an offscreen surface to a rendertarget, the source
3906          * surface is not required to have a palette. Our rendering / conversion
3907          * code further down the road retrieves the palette from the surface, so
3908          * it must have a palette set. */
3909         if (Src->resource.format_desc->format == WINED3DFMT_P8_UINT && !Src->palette)
3910         {
3911             paletteOverride = TRUE;
3912             TRACE("Source surface (%p) lacks palette, overriding palette with palette %p of destination surface (%p)\n", Src, This->palette, This);
3913             Src->palette = This->palette;
3914         }
3915
3916         if (wined3d_settings.offscreen_rendering_mode == ORM_FBO
3917                 && myDevice->adapter->gl_info.fbo_ops.glBlitFramebuffer
3918                 && !(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE))
3919                 && surface_can_stretch_rect(Src, This))
3920         {
3921             TRACE("Using stretch_rect_fbo\n");
3922             /* The source is always a texture, but never the currently active render target, and the texture
3923              * contents are never upside down
3924              */
3925             stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, (WINED3DRECT *) &SourceRectangle,
3926                               (IWineD3DSurface *)This, &rect, Filter, FALSE);
3927
3928             /* Clear the palette as the surface didn't have a palette attached, it would confuse GetPalette and other calls */
3929             if(paletteOverride)
3930                 Src->palette = NULL;
3931             return WINED3D_OK;
3932         }
3933
3934         if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
3935             /* Fall back to software */
3936             WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
3937                     SourceRectangle.left, SourceRectangle.top,
3938                     SourceRectangle.right, SourceRectangle.bottom);
3939             return WINED3DERR_INVALIDCALL;
3940         }
3941
3942         /* Color keying: Check if we have to do a color keyed blt,
3943          * and if not check if a color key is activated.
3944          *
3945          * Just modify the color keying parameters in the surface and restore them afterwards
3946          * The surface keeps track of the color key last used to load the opengl surface.
3947          * PreLoad will catch the change to the flags and color key and reload if necessary.
3948          */
3949         if(Flags & WINEDDBLT_KEYSRC) {
3950             /* Use color key from surface */
3951         } else if(Flags & WINEDDBLT_KEYSRCOVERRIDE) {
3952             /* Use color key from DDBltFx */
3953             Src->CKeyFlags |= WINEDDSD_CKSRCBLT;
3954             Src->SrcBltCKey = DDBltFx->ddckSrcColorkey;
3955         } else {
3956             /* Do not use color key */
3957             Src->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3958         }
3959
3960         /* Now load the surface */
3961         surface_internal_preload((IWineD3DSurface *) Src, SRGB_RGB);
3962
3963         /* Activate the destination context, set it up for blitting */
3964         context = context_acquire(myDevice, (IWineD3DSurface *)This, CTXUSAGE_BLIT);
3965
3966         /* The coordinates of the ddraw front buffer are always fullscreen ('screen coordinates',
3967          * while OpenGL coordinates are window relative.
3968          * Also beware of the origin difference(top left vs bottom left).
3969          * Also beware that the front buffer's surface size is screen width x screen height,
3970          * whereas the real gl drawable size is the size of the window.
3971          */
3972         if (dstSwapchain && (IWineD3DSurface *)This == dstSwapchain->frontBuffer) {
3973             RECT windowsize;
3974             POINT offset = {0,0};
3975             UINT h;
3976             ClientToScreen(dstSwapchain->win_handle, &offset);
3977             GetClientRect(dstSwapchain->win_handle, &windowsize);
3978             h = windowsize.bottom - windowsize.top;
3979             rect.x1 -= offset.x; rect.x2 -=offset.x;
3980             rect.y1 -= offset.y; rect.y2 -=offset.y;
3981             rect.y1 += This->currentDesc.Height - h; rect.y2 += This->currentDesc.Height - h;
3982         }
3983
3984         if (!is_identity_fixup(This->resource.format_desc->color_fixup))
3985         {
3986             FIXME("Destination format %s has a fixup, this is not supported.\n",
3987                     debug_d3dformat(This->resource.format_desc->format));
3988             dump_color_fixup_desc(This->resource.format_desc->color_fixup);
3989         }
3990
3991         if (!myDevice->blitter->color_fixup_supported(Src->resource.format_desc->color_fixup))
3992         {
3993             FIXME("Source format %s has an unsupported fixup:\n",
3994                     debug_d3dformat(Src->resource.format_desc->format));
3995             dump_color_fixup_desc(Src->resource.format_desc->color_fixup);
3996         }
3997
3998         myDevice->blitter->set_shader((IWineD3DDevice *) myDevice, Src->resource.format_desc,
3999                 Src->texture_target, Src->pow2Width, Src->pow2Height);
4000
4001         ENTER_GL();
4002
4003         /* Bind the texture */
4004         glBindTexture(Src->texture_target, Src->texture_name);
4005         checkGLcall("glBindTexture");
4006
4007         /* Filtering for StretchRect */
4008         glTexParameteri(Src->texture_target, GL_TEXTURE_MAG_FILTER,
4009                 wined3d_gl_mag_filter(magLookup, Filter));
4010         checkGLcall("glTexParameteri");
4011         glTexParameteri(Src->texture_target, GL_TEXTURE_MIN_FILTER,
4012                 wined3d_gl_min_mip_filter(minMipLookup, Filter, WINED3DTEXF_NONE));
4013         checkGLcall("glTexParameteri");
4014         glTexParameteri(Src->texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP);
4015         glTexParameteri(Src->texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP);
4016         glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
4017         checkGLcall("glTexEnvi");
4018
4019         /* This is for color keying */
4020         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
4021             glEnable(GL_ALPHA_TEST);
4022             checkGLcall("glEnable(GL_ALPHA_TEST)");
4023
4024             /* When the primary render target uses P8, the alpha component contains the palette index.
4025              * Which means that the colorkey is one of the palette entries. In other cases pixels that
4026              * should be masked away have alpha set to 0. */
4027             if(primary_render_target_is_p8(myDevice))
4028                 glAlphaFunc(GL_NOTEQUAL, (float)Src->SrcBltCKey.dwColorSpaceLowValue / 256.0f);
4029             else
4030                 glAlphaFunc(GL_NOTEQUAL, 0.0f);
4031             checkGLcall("glAlphaFunc");
4032         } else {
4033             glDisable(GL_ALPHA_TEST);
4034             checkGLcall("glDisable(GL_ALPHA_TEST)");
4035         }
4036
4037         /* Draw a textured quad
4038          */
4039         glBegin(GL_QUADS);
4040
4041         glColor3f(1.0f, 1.0f, 1.0f);
4042         glTexCoord2f(glTexCoord[0], glTexCoord[2]);
4043         glVertex3f(rect.x1, rect.y1, 0.0f);
4044
4045         glTexCoord2f(glTexCoord[0], glTexCoord[3]);
4046         glVertex3f(rect.x1, rect.y2, 0.0f);
4047
4048         glTexCoord2f(glTexCoord[1], glTexCoord[3]);
4049         glVertex3f(rect.x2, rect.y2, 0.0f);
4050
4051         glTexCoord2f(glTexCoord[1], glTexCoord[2]);
4052         glVertex3f(rect.x2, rect.y1, 0.0f);
4053
4054         glEnd();
4055         checkGLcall("glEnd");
4056
4057         if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
4058             glDisable(GL_ALPHA_TEST);
4059             checkGLcall("glDisable(GL_ALPHA_TEST)");
4060         }
4061
4062         glBindTexture(Src->texture_target, 0);
4063         checkGLcall("glBindTexture(Src->texture_target, 0)");
4064
4065         /* Restore the color key parameters */
4066         Src->CKeyFlags = oldCKeyFlags;
4067         Src->SrcBltCKey = oldBltCKey;
4068
4069         /* Clear the palette as the surface didn't have a palette attached, it would confuse GetPalette and other calls */
4070         if(paletteOverride)
4071             Src->palette = NULL;
4072
4073         LEAVE_GL();
4074
4075         /* Leave the opengl state valid for blitting */
4076         myDevice->blitter->unset_shader((IWineD3DDevice *) myDevice);
4077
4078         wglFlush(); /* Flush to ensure ordering across contexts. */
4079
4080         context_release(context);
4081
4082         /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
4083         /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
4084          * is outdated now
4085          */
4086         IWineD3DSurface_ModifyLocation((IWineD3DSurface *) This, SFLAG_INDRAWABLE, TRUE);
4087
4088         return WINED3D_OK;
4089     } else {
4090         /* Source-Less Blit to render target */
4091         if (Flags & WINEDDBLT_COLORFILL) {
4092             /* This is easy to handle for the D3D Device... */
4093             DWORD color;
4094
4095             TRACE("Colorfill\n");
4096
4097             /* This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0] || dstSwapchain
4098                 must be true if we are here */
4099             if (This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0] &&
4100                     !(This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer ||
4101                       (dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]))) {
4102                 TRACE("Surface is higher back buffer, falling back to software\n");
4103                 return WINED3DERR_INVALIDCALL;
4104             }
4105
4106             /* The color as given in the Blt function is in the format of the frame-buffer...
4107              * 'clear' expect it in ARGB format => we need to do some conversion :-)
4108              */
4109             if (This->resource.format_desc->format == WINED3DFMT_P8_UINT)
4110             {
4111                 DWORD alpha;
4112
4113                 if (primary_render_target_is_p8(myDevice)) alpha = DDBltFx->u5.dwFillColor << 24;
4114                 else alpha = 0xFF000000;
4115
4116                 if (This->palette) {
4117                     color = (alpha |
4118                             (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
4119                             (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
4120                             (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
4121                 } else {
4122                     color = alpha;
4123                 }
4124             }
4125             else if (This->resource.format_desc->format == WINED3DFMT_B5G6R5_UNORM)
4126             {
4127                 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
4128                     color = 0xFFFFFFFF;
4129                 } else {
4130                     color = ((0xFF000000) |
4131                             ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
4132                             ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
4133                             ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
4134                 }
4135             }
4136             else if (This->resource.format_desc->format == WINED3DFMT_B8G8R8_UNORM
4137                     || This->resource.format_desc->format == WINED3DFMT_B8G8R8X8_UNORM)
4138             {
4139                 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
4140             }
4141             else if (This->resource.format_desc->format == WINED3DFMT_B8G8R8A8_UNORM)
4142             {
4143                 color = DDBltFx->u5.dwFillColor;
4144             }
4145             else {
4146                 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
4147                 return WINED3DERR_INVALIDCALL;
4148             }
4149
4150             TRACE("(%p) executing Render Target override, color = %x\n", This, color);
4151             IWineD3DDeviceImpl_ClearSurface(myDevice, This, 1 /* Number of rectangles */,
4152                     &rect, WINED3DCLEAR_TARGET, color, 0.0f /* Z */, 0 /* Stencil */);
4153             return WINED3D_OK;
4154         }
4155     }
4156
4157     /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
4158     TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
4159     return WINED3DERR_INVALIDCALL;
4160 }
4161
4162 static HRESULT IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, const RECT *DestRect,
4163         IWineD3DSurface *SrcSurface, const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx)
4164 {
4165     IWineD3DDeviceImpl *myDevice = This->resource.device;
4166     float depth;
4167
4168     if (Flags & WINEDDBLT_DEPTHFILL) {
4169         switch(This->resource.format_desc->format)
4170         {
4171             case WINED3DFMT_D16_UNORM:
4172                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000ffff;
4173                 break;
4174             case WINED3DFMT_S1_UINT_D15_UNORM:
4175                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x0000fffe;
4176                 break;
4177             case WINED3DFMT_D24_UNORM_S8_UINT:
4178             case WINED3DFMT_X8D24_UNORM:
4179                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0x00ffffff;
4180                 break;
4181             case WINED3DFMT_D32_UNORM:
4182                 depth = (float) DDBltFx->u5.dwFillDepth / (float) 0xffffffff;
4183                 break;
4184             default:
4185                 depth = 0.0f;
4186                 ERR("Unexpected format for depth fill: %s\n", debug_d3dformat(This->resource.format_desc->format));
4187         }
4188
4189         return IWineD3DDevice_Clear((IWineD3DDevice *) myDevice,
4190                                     DestRect == NULL ? 0 : 1,
4191                                     (const WINED3DRECT *)DestRect,
4192                                     WINED3DCLEAR_ZBUFFER,
4193                                     0x00000000,
4194                                     depth,
4195                                     0x00000000);
4196     }
4197
4198     FIXME("(%p): Unsupp depthstencil blit\n", This);
4199     return WINED3DERR_INVALIDCALL;
4200 }
4201
4202 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, const RECT *DestRect, IWineD3DSurface *SrcSurface,
4203         const RECT *SrcRect, DWORD Flags, const WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
4204     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4205     IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
4206     IWineD3DDeviceImpl *myDevice = This->resource.device;
4207
4208     TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
4209     TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
4210
4211     if ( (This->Flags & SFLAG_LOCKED) || ((Src != NULL) && (Src->Flags & SFLAG_LOCKED)))
4212     {
4213         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
4214         return WINEDDERR_SURFACEBUSY;
4215     }
4216
4217     /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair,
4218      * except depth blits, which seem to work
4219      */
4220     if(iface == myDevice->stencilBufferTarget || (SrcSurface && SrcSurface == myDevice->stencilBufferTarget)) {
4221         if(myDevice->inScene && !(Flags & WINEDDBLT_DEPTHFILL)) {
4222             TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
4223             return WINED3DERR_INVALIDCALL;
4224         } else if(IWineD3DSurfaceImpl_BltZ(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) {
4225             TRACE("Z Blit override handled the blit\n");
4226             return WINED3D_OK;
4227         }
4228     }
4229
4230     /* Special cases for RenderTargets */
4231     if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
4232         ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
4233         if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter) == WINED3D_OK) return WINED3D_OK;
4234     }
4235
4236     /* For the rest call the X11 surface implementation.
4237      * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
4238      * other Blts are rather rare
4239      */
4240     return IWineD3DBaseSurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter);
4241 }
4242
4243 static HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty,
4244         IWineD3DSurface *Source, const RECT *rsrc, DWORD trans)
4245 {
4246     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4247     IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
4248     IWineD3DDeviceImpl *myDevice = This->resource.device;
4249
4250     TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
4251
4252     if ( (This->Flags & SFLAG_LOCKED) || (srcImpl->Flags & SFLAG_LOCKED))
4253     {
4254         WARN(" Surface is busy, returning DDERR_SURFACEBUSY\n");
4255         return WINEDDERR_SURFACEBUSY;
4256     }
4257
4258     if(myDevice->inScene &&
4259        (iface == myDevice->stencilBufferTarget ||
4260        (Source == myDevice->stencilBufferTarget))) {
4261         TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
4262         return WINED3DERR_INVALIDCALL;
4263     }
4264
4265     /* Special cases for RenderTargets */
4266     if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
4267         (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
4268
4269         RECT SrcRect, DstRect;
4270         DWORD Flags=0;
4271
4272         if(rsrc) {
4273             SrcRect.left = rsrc->left;
4274             SrcRect.top= rsrc->top;
4275             SrcRect.bottom = rsrc->bottom;
4276             SrcRect.right = rsrc->right;
4277         } else {
4278             SrcRect.left = 0;
4279             SrcRect.top = 0;
4280             SrcRect.right = srcImpl->currentDesc.Width;
4281             SrcRect.bottom = srcImpl->currentDesc.Height;
4282         }
4283
4284         DstRect.left = dstx;
4285         DstRect.top=dsty;
4286         DstRect.right = dstx + SrcRect.right - SrcRect.left;
4287         DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
4288
4289         /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
4290         if(trans & WINEDDBLTFAST_SRCCOLORKEY)
4291             Flags |= WINEDDBLT_KEYSRC;
4292         if(trans & WINEDDBLTFAST_DESTCOLORKEY)
4293             Flags |= WINEDDBLT_KEYDEST;
4294         if(trans & WINEDDBLTFAST_WAIT)
4295             Flags |= WINEDDBLT_WAIT;
4296         if(trans & WINEDDBLTFAST_DONOTWAIT)
4297             Flags |= WINEDDBLT_DONOTWAIT;
4298
4299         if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL, WINED3DTEXF_POINT) == WINED3D_OK) return WINED3D_OK;
4300     }
4301
4302
4303     return IWineD3DBaseSurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
4304 }
4305
4306 static HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface)
4307 {
4308     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4309     RGBQUAD col[256];
4310     IWineD3DPaletteImpl *pal = This->palette;
4311     unsigned int n;
4312     TRACE("(%p)\n", This);
4313
4314     if (!pal) return WINED3D_OK;
4315
4316     if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
4317             || This->resource.format_desc->format == WINED3DFMT_P8_UINT_A8_UNORM)
4318     {
4319         int bpp;
4320         GLenum format, internal, type;
4321         CONVERT_TYPES convert;
4322
4323         /* Check if we are using a RTL mode which uses texturing for uploads */
4324         BOOL use_texture = (wined3d_settings.rendertargetlock_mode == RTL_READTEX);
4325
4326         /* Check if we have hardware palette conversion if we have convert is set to NO_CONVERSION */
4327         d3dfmt_get_conv(This, TRUE, use_texture, &format, &internal, &type, &convert, &bpp, FALSE);
4328
4329         if((This->resource.usage & WINED3DUSAGE_RENDERTARGET) && (convert == NO_CONVERSION))
4330         {
4331             IWineD3DDeviceImpl *device = This->resource.device;
4332             struct wined3d_context *context;
4333
4334             /* Make sure the texture is up to date. This call doesn't do anything if the texture is already up to date. */
4335             IWineD3DSurface_LoadLocation(iface, SFLAG_INTEXTURE, NULL);
4336
4337             /* We want to force a palette refresh, so mark the drawable as not being up to date */
4338             IWineD3DSurface_ModifyLocation(iface, SFLAG_INDRAWABLE, FALSE);
4339
4340             /* Re-upload the palette */
4341             context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4342             d3dfmt_p8_upload_palette(iface, convert);
4343             context_release(context);
4344         } else {
4345             if(!(This->Flags & SFLAG_INSYSMEM)) {
4346                 TRACE("Palette changed with surface that does not have an up to date system memory copy\n");
4347                 IWineD3DSurface_LoadLocation(iface, SFLAG_INSYSMEM, NULL);
4348             }
4349             TRACE("Dirtifying surface\n");
4350             IWineD3DSurface_ModifyLocation(iface, SFLAG_INSYSMEM, TRUE);
4351         }
4352     }
4353
4354     if(This->Flags & SFLAG_DIBSECTION) {
4355         TRACE("(%p): Updating the hdc's palette\n", This);
4356         for (n=0; n<256; n++) {
4357             col[n].rgbRed   = pal->palents[n].peRed;
4358             col[n].rgbGreen = pal->palents[n].peGreen;
4359             col[n].rgbBlue  = pal->palents[n].peBlue;
4360             col[n].rgbReserved = 0;
4361         }
4362         SetDIBColorTable(This->hDC, 0, 256, col);
4363     }
4364
4365     /* Propagate the changes to the drawable when we have a palette. */
4366     if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
4367         IWineD3DSurface_LoadLocation(iface, SFLAG_INDRAWABLE, NULL);
4368
4369     return WINED3D_OK;
4370 }
4371
4372 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
4373     /** Check against the maximum texture sizes supported by the video card **/
4374     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4375     const struct wined3d_gl_info *gl_info = &This->resource.device->adapter->gl_info;
4376     unsigned int pow2Width, pow2Height;
4377
4378     This->texture_name = 0;
4379     This->texture_target = GL_TEXTURE_2D;
4380
4381     /* Non-power2 support */
4382     if (gl_info->supported[ARB_TEXTURE_NON_POWER_OF_TWO] || gl_info->supported[WINE_NORMALIZED_TEXRECT])
4383     {
4384         pow2Width = This->currentDesc.Width;
4385         pow2Height = This->currentDesc.Height;
4386     }
4387     else
4388     {
4389         /* Find the nearest pow2 match */
4390         pow2Width = pow2Height = 1;
4391         while (pow2Width < This->currentDesc.Width) pow2Width <<= 1;
4392         while (pow2Height < This->currentDesc.Height) pow2Height <<= 1;
4393     }
4394     This->pow2Width  = pow2Width;
4395     This->pow2Height = pow2Height;
4396
4397     if (pow2Width > This->currentDesc.Width || pow2Height > This->currentDesc.Height) {
4398         /** TODO: add support for non power two compressed textures **/
4399         if (This->resource.format_desc->Flags & WINED3DFMT_FLAG_COMPRESSED)
4400         {
4401             FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
4402                   This, This->currentDesc.Width, This->currentDesc.Height);
4403             return WINED3DERR_NOTAVAILABLE;
4404         }
4405     }
4406
4407     if(pow2Width != This->currentDesc.Width ||
4408        pow2Height != This->currentDesc.Height) {
4409         This->Flags |= SFLAG_NONPOW2;
4410     }
4411
4412     TRACE("%p\n", This);
4413     if ((This->pow2Width > gl_info->limits.texture_size || This->pow2Height > gl_info->limits.texture_size)
4414             && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL)))
4415     {
4416         /* one of three options
4417         1: Do the same as we do with nonpow 2 and scale the texture, (any texture ops would require the texture to be scaled which is potentially slow)
4418         2: Set the texture to the maximum size (bad idea)
4419         3:    WARN and return WINED3DERR_NOTAVAILABLE;
4420         4: Create the surface, but allow it to be used only for DirectDraw Blts. Some apps(e.g. Swat 3) create textures with a Height of 16 and a Width > 3000 and blt 16x16 letter areas from them to the render target.
4421         */
4422         if(This->resource.pool == WINED3DPOOL_DEFAULT || This->resource.pool == WINED3DPOOL_MANAGED)
4423         {
4424             WARN("(%p) Unable to allocate a surface which exceeds the maximum OpenGL texture size\n", This);
4425             return WINED3DERR_NOTAVAILABLE;
4426         }
4427
4428         /* We should never use this surface in combination with OpenGL! */
4429         TRACE("(%p) Creating an oversized surface: %ux%u\n", This, This->pow2Width, This->pow2Height);
4430
4431         /* This will be initialized on the first blt */
4432         This->glRect.left = 0;
4433         This->glRect.top = 0;
4434         This->glRect.right = 0;
4435         This->glRect.bottom = 0;
4436     } else {
4437         /* Don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
4438            is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
4439            doesn't work in combination with ARB_TEXTURE_RECTANGLE.
4440         */
4441         if (This->Flags & SFLAG_NONPOW2 && gl_info->supported[ARB_TEXTURE_RECTANGLE]
4442                 && !(This->resource.format_desc->format == WINED3DFMT_P8_UINT
4443                 && gl_info->supported[EXT_PALETTED_TEXTURE]
4444                 && wined3d_settings.rendertargetlock_mode == RTL_READTEX))
4445         {
4446             This->texture_target = GL_TEXTURE_RECTANGLE_ARB;
4447             This->pow2Width  = This->currentDesc.Width;
4448             This->pow2Height = This->currentDesc.Height;
4449             This->Flags &= ~(SFLAG_NONPOW2 | SFLAG_NORMCOORD);
4450         }
4451
4452         This->glRect.left = 0;
4453         This->glRect.top = 0;
4454         This->glRect.right = This->pow2Width;
4455         This->glRect.bottom = This->pow2Height;
4456     }
4457
4458     if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
4459         switch(wined3d_settings.offscreen_rendering_mode) {
4460             case ORM_FBO:        This->get_drawable_size = get_drawable_size_fbo;        break;
4461             case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
4462         }
4463     }
4464
4465     This->Flags |= SFLAG_INSYSMEM;
4466
4467     return WINED3D_OK;
4468 }
4469
4470 /* GL locking is done by the caller */
4471 static void surface_depth_blt(IWineD3DSurfaceImpl *This, GLuint texture, GLsizei w, GLsizei h, GLenum target)
4472 {
4473     IWineD3DDeviceImpl *device = This->resource.device;
4474     struct blt_info info;
4475     GLint old_binding = 0;
4476
4477     glPushAttrib(GL_ENABLE_BIT | GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT);
4478
4479     glDisable(GL_CULL_FACE);
4480     glDisable(GL_BLEND);
4481     glDisable(GL_ALPHA_TEST);
4482     glDisable(GL_SCISSOR_TEST);
4483     glDisable(GL_STENCIL_TEST);
4484     glEnable(GL_DEPTH_TEST);
4485     glDepthFunc(GL_ALWAYS);
4486     glDepthMask(GL_TRUE);
4487     glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
4488     glViewport(0, 0, w, h);
4489
4490     surface_get_blt_info(target, NULL, w, h, &info);
4491     GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
4492     glGetIntegerv(info.binding, &old_binding);
4493     glBindTexture(info.bind_target, texture);
4494
4495     device->shader_backend->shader_select_depth_blt((IWineD3DDevice *)device, info.tex_type);
4496
4497     glBegin(GL_TRIANGLE_STRIP);
4498     glTexCoord3fv(info.coords[0]);
4499     glVertex2f(-1.0f, -1.0f);
4500     glTexCoord3fv(info.coords[1]);
4501     glVertex2f(1.0f, -1.0f);
4502     glTexCoord3fv(info.coords[2]);
4503     glVertex2f(-1.0f, 1.0f);
4504     glTexCoord3fv(info.coords[3]);
4505     glVertex2f(1.0f, 1.0f);
4506     glEnd();
4507
4508     glBindTexture(info.bind_target, old_binding);
4509
4510     glPopAttrib();
4511
4512     device->shader_backend->shader_deselect_depth_blt((IWineD3DDevice *)device);
4513 }
4514
4515 void surface_modify_ds_location(IWineD3DSurface *iface, DWORD location) {
4516     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4517
4518     TRACE("(%p) New location %#x\n", This, location);
4519
4520     if (location & ~SFLAG_DS_LOCATIONS) {
4521         FIXME("(%p) Invalid location (%#x) specified\n", This, location);
4522     }
4523
4524     This->Flags &= ~SFLAG_DS_LOCATIONS;
4525     This->Flags |= location;
4526 }
4527
4528 /* Context activation is done by the caller. */
4529 void surface_load_ds_location(IWineD3DSurface *iface, struct wined3d_context *context, DWORD location)
4530 {
4531     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
4532     IWineD3DDeviceImpl *device = This->resource.device;
4533     const struct wined3d_gl_info *gl_info = context->gl_info;
4534
4535     TRACE("(%p) New location %#x\n", This, location);
4536
4537     /* TODO: Make this work for modes other than FBO */
4538     if (wined3d_settings.offscreen_rendering_mode != ORM_FBO) return;
4539
4540     if (This->Flags & location) {
4541         TRACE("(%p) Location (%#x) is already up to date\n", This, location);
4542         return;
4543     }
4544
4545     if (This->current_renderbuffer) {
4546         FIXME("(%p) Not supported with fixed up depth stencil\n", This);
4547         return;
4548     }
4549
4550     if (location == SFLAG_DS_OFFSCREEN) {
4551         if (This->Flags & SFLAG_DS_ONSCREEN) {
4552             GLint old_binding = 0;
4553             GLenum bind_target;
4554
4555             TRACE("(%p) Copying onscreen depth buffer to depth texture\n", This);
4556
4557             ENTER_GL();
4558
4559             if (!device->depth_blt_texture) {
4560                 glGenTextures(1, &device->depth_blt_texture);
4561             }
4562
4563             /* Note that we use depth_blt here as well, rather than glCopyTexImage2D
4564              * directly on the FBO texture. That's because we need to flip. */
4565             context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4566             if (This->texture_target == GL_TEXTURE_RECTANGLE_ARB)
4567             {
4568                 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
4569                 bind_target = GL_TEXTURE_RECTANGLE_ARB;
4570             } else {
4571                 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
4572                 bind_target = GL_TEXTURE_2D;
4573             }
4574             glBindTexture(bind_target, device->depth_blt_texture);
4575             glCopyTexImage2D(bind_target, This->texture_level, This->resource.format_desc->glInternal,
4576                     0, 0, This->currentDesc.Width, This->currentDesc.Height, 0);
4577             glTexParameteri(bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4578             glTexParameteri(bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4579             glTexParameteri(bind_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
4580             glTexParameteri(bind_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
4581             glTexParameteri(bind_target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
4582             glTexParameteri(bind_target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
4583             glBindTexture(bind_target, old_binding);
4584
4585             /* Setup the destination */
4586             if (!device->depth_blt_rb) {
4587                 gl_info->fbo_ops.glGenRenderbuffers(1, &device->depth_blt_rb);
4588                 checkGLcall("glGenRenderbuffersEXT");
4589             }
4590             if (device->depth_blt_rb_w != This->currentDesc.Width
4591                     || device->depth_blt_rb_h != This->currentDesc.Height) {
4592                 gl_info->fbo_ops.glBindRenderbuffer(GL_RENDERBUFFER, device->depth_blt_rb);
4593                 checkGLcall("glBindRenderbufferEXT");
4594                 gl_info->fbo_ops.glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8,
4595                         This->currentDesc.Width, This->currentDesc.Height);
4596                 checkGLcall("glRenderbufferStorageEXT");
4597                 device->depth_blt_rb_w = This->currentDesc.Width;
4598                 device->depth_blt_rb_h = This->currentDesc.Height;
4599             }
4600
4601             context_bind_fbo(context, GL_FRAMEBUFFER, &context->dst_fbo);
4602             gl_info->fbo_ops.glFramebufferRenderbuffer(GL_FRAMEBUFFER,
4603                     GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, device->depth_blt_rb);
4604             checkGLcall("glFramebufferRenderbufferEXT");
4605             context_attach_depth_stencil_fbo(context, GL_FRAMEBUFFER, iface, FALSE);
4606
4607             /* Do the actual blit */
4608             surface_depth_blt(This, device->depth_blt_texture, This->currentDesc.Width, This->currentDesc.Height, bind_target);
4609             checkGLcall("depth_blt");
4610
4611             if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4612             else context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4613
4614             LEAVE_GL();
4615
4616             wglFlush(); /* Flush to ensure ordering across contexts. */
4617         }
4618         else
4619         {
4620             FIXME("No up to date depth stencil location\n");
4621         }
4622     } else if (location == SFLAG_DS_ONSCREEN) {
4623         if (This->Flags & SFLAG_DS_OFFSCREEN) {
4624             TRACE("(%p) Copying depth texture to onscreen depth buffer\n", This);
4625
4626             ENTER_GL();
4627
4628             context_bind_fbo(context, GL_FRAMEBUFFER, NULL);
4629             surface_depth_blt(This, This->texture_name, This->currentDesc.Width,
4630                     This->currentDesc.Height, This->texture_target);
4631             checkGLcall("depth_blt");
4632
4633             if (context->current_fbo) context_bind_fbo(context, GL_FRAMEBUFFER, &context->current_fbo->id);
4634
4635             LEAVE_GL();
4636
4637             wglFlush(); /* Flush to ensure ordering across contexts. */
4638         }
4639         else
4640         {
4641             FIXME("No up to date depth stencil location\n");
4642         }
4643     } else {
4644         ERR("(%p) Invalid location (%#x) specified\n", This, location);
4645     }
4646
4647     This->Flags |= location;
4648 }
4649
4650 static void WINAPI IWineD3DSurfaceImpl_ModifyLocation(IWineD3DSurface *iface, DWORD flag, BOOL persistent) {
4651     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4652     IWineD3DBaseTexture *texture;
4653     IWineD3DSurfaceImpl *overlay;
4654
4655     TRACE("(%p)->(%s, %s)\n", iface, debug_surflocation(flag),
4656           persistent ? "TRUE" : "FALSE");
4657
4658     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4659         if (surface_is_offscreen(iface))
4660         {
4661             /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
4662             if (flag & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE)) flag |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
4663         }
4664         else
4665         {
4666             TRACE("Surface %p is an onscreen surface\n", iface);
4667         }
4668     }
4669
4670     if(persistent) {
4671         if(((This->Flags & SFLAG_INTEXTURE) && !(flag & SFLAG_INTEXTURE)) ||
4672            ((This->Flags & SFLAG_INSRGBTEX) && !(flag & SFLAG_INSRGBTEX))) {
4673             if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
4674                 TRACE("Passing to container\n");
4675                 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4676                 IWineD3DBaseTexture_Release(texture);
4677             }
4678         }
4679         This->Flags &= ~SFLAG_LOCATIONS;
4680         This->Flags |= flag;
4681
4682         /* Redraw emulated overlays, if any */
4683         if(flag & SFLAG_INDRAWABLE && !list_empty(&This->overlays)) {
4684             LIST_FOR_EACH_ENTRY(overlay, &This->overlays, IWineD3DSurfaceImpl, overlay_entry) {
4685                 IWineD3DSurface_DrawOverlay((IWineD3DSurface *) overlay);
4686             }
4687         }
4688     } else {
4689         if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) && (flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))) {
4690             if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&texture) == WINED3D_OK) {
4691                 TRACE("Passing to container\n");
4692                 IWineD3DBaseTexture_SetDirty(texture, TRUE);
4693                 IWineD3DBaseTexture_Release(texture);
4694             }
4695         }
4696         This->Flags &= ~flag;
4697     }
4698
4699     if(!(This->Flags & SFLAG_LOCATIONS)) {
4700         ERR("%p: Surface does not have any up to date location\n", This);
4701     }
4702 }
4703
4704 static inline void surface_blt_to_drawable(IWineD3DSurfaceImpl *This, const RECT *rect_in)
4705 {
4706     IWineD3DDeviceImpl *device = This->resource.device;
4707     IWineD3DBaseTextureImpl *texture;
4708     struct wined3d_context *context;
4709     RECT rect;
4710     struct blt_info info;
4711
4712     if(rect_in) {
4713         rect = *rect_in;
4714     } else {
4715         rect.left = 0;
4716         rect.top = 0;
4717         rect.right = This->currentDesc.Width;
4718         rect.bottom = This->currentDesc.Height;
4719     }
4720
4721     surface_get_blt_info(This->texture_target, &rect, This->pow2Width, This->pow2Height, &info);
4722
4723     context = context_acquire(device, (IWineD3DSurface*)This, CTXUSAGE_BLIT);
4724
4725     ENTER_GL();
4726
4727     glEnable(info.bind_target);
4728     checkGLcall("glEnable(bind_target)");
4729     glBindTexture(info.bind_target, This->texture_name);
4730     checkGLcall("glBindTexture(bind_target, This->texture_name)");
4731     glTexParameteri(info.bind_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4732     checkGLcall("glTexParameteri");
4733     glTexParameteri(info.bind_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4734     checkGLcall("glTexParameteri");
4735
4736     if (context->render_offscreen)
4737     {
4738         LONG tmp = rect.top;
4739         rect.top = rect.bottom;
4740         rect.bottom = tmp;
4741     }
4742
4743     glBegin(GL_TRIANGLE_STRIP);
4744     glTexCoord3fv(info.coords[0]);
4745     glVertex2i(rect.left, rect.top);
4746
4747     glTexCoord3fv(info.coords[1]);
4748     glVertex2i(rect.right, rect.top);
4749
4750     glTexCoord3fv(info.coords[2]);
4751     glVertex2i(rect.left, rect.bottom);
4752
4753     glTexCoord3fv(info.coords[3]);
4754     glVertex2i(rect.right, rect.bottom);
4755     glEnd();
4756
4757     glDisable(info.bind_target);
4758     checkGLcall("glDisable(bind_target)");
4759
4760     LEAVE_GL();
4761
4762     wglFlush(); /* Flush to ensure ordering across contexts. */
4763
4764     /* We changed the filtering settings on the texture. Inform the
4765      * container about this to get the filters reset properly next draw. */
4766     if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)This, &IID_IWineD3DBaseTexture, (void **)&texture)))
4767     {
4768         texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
4769         texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
4770         texture->baseTexture.texture_rgb.states[WINED3DTEXSTA_MIPFILTER] = WINED3DTEXF_NONE;
4771         IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture);
4772     }
4773
4774     context_release(context);
4775 }
4776
4777 /*****************************************************************************
4778  * IWineD3DSurface::LoadLocation
4779  *
4780  * Copies the current surface data from wherever it is to the requested
4781  * location. The location is one of the surface flags, SFLAG_INSYSMEM,
4782  * SFLAG_INTEXTURE and SFLAG_INDRAWABLE. When the surface is current in
4783  * multiple locations, the gl texture is preferred over the drawable, which is
4784  * preferred over system memory. The PBO counts as system memory. If rect is
4785  * not NULL, only the specified rectangle is copied (only supported for
4786  * sysmem<->drawable copies at the moment). If rect is NULL, the destination
4787  * location is marked up to date after the copy.
4788  *
4789  * Parameters:
4790  *  flag: Surface location flag to be updated
4791  *  rect: rectangle to be copied
4792  *
4793  * Returns:
4794  *  WINED3D_OK on success
4795  *  WINED3DERR_DEVICELOST on an internal error
4796  *
4797  *****************************************************************************/
4798 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadLocation(IWineD3DSurface *iface, DWORD flag, const RECT *rect) {
4799     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
4800     IWineD3DDeviceImpl *device = This->resource.device;
4801     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
4802     GLenum format, internal, type;
4803     CONVERT_TYPES convert;
4804     int bpp;
4805     int width, pitch, outpitch;
4806     BYTE *mem;
4807     BOOL drawable_read_ok = TRUE;
4808     BOOL in_fbo = FALSE;
4809
4810     if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4811         if (surface_is_offscreen(iface))
4812         {
4813             /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets.
4814              * Prefer SFLAG_INTEXTURE. */
4815             if (flag == SFLAG_INDRAWABLE) flag = SFLAG_INTEXTURE;
4816             drawable_read_ok = FALSE;
4817             in_fbo = TRUE;
4818         }
4819         else
4820         {
4821             TRACE("Surface %p is an onscreen surface\n", iface);
4822         }
4823     }
4824
4825     TRACE("(%p)->(%s, %p)\n", iface, debug_surflocation(flag), rect);
4826     if(rect) {
4827         TRACE("Rectangle: (%d,%d)-(%d,%d)\n", rect->left, rect->top, rect->right, rect->bottom);
4828     }
4829
4830     if(This->Flags & flag) {
4831         TRACE("Location already up to date\n");
4832         return WINED3D_OK;
4833     }
4834
4835     if(!(This->Flags & SFLAG_LOCATIONS)) {
4836         ERR("%p: Surface does not have any up to date location\n", This);
4837         This->Flags |= SFLAG_LOST;
4838         return WINED3DERR_DEVICELOST;
4839     }
4840
4841     if(flag == SFLAG_INSYSMEM) {
4842         surface_prepare_system_memory(This);
4843
4844         /* Download the surface to system memory */
4845         if (This->Flags & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX))
4846         {
4847             struct wined3d_context *context = NULL;
4848
4849             if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4850
4851             surface_bind_and_dirtify(This, !(This->Flags & SFLAG_INTEXTURE));
4852             surface_download_data(This);
4853
4854             if (context) context_release(context);
4855         }
4856         else
4857         {
4858             /* Note: It might be faster to download into a texture first. */
4859             read_from_framebuffer(This, rect,
4860                                   This->resource.allocatedMemory,
4861                                   IWineD3DSurface_GetPitch(iface));
4862         }
4863     } else if(flag == SFLAG_INDRAWABLE) {
4864         if(This->Flags & SFLAG_INTEXTURE) {
4865             surface_blt_to_drawable(This, rect);
4866         } else {
4867             if((This->Flags & SFLAG_LOCATIONS) == SFLAG_INSRGBTEX) {
4868                 /* This needs a shader to convert the srgb data sampled from the GL texture into RGB
4869                  * values, otherwise we get incorrect values in the target. For now go the slow way
4870                  * via a system memory copy
4871                  */
4872                 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4873             }
4874
4875             d3dfmt_get_conv(This, TRUE /* We need color keying */, FALSE /* We won't use textures */, &format, &internal, &type, &convert, &bpp, FALSE);
4876
4877             /* The width is in 'length' not in bytes */
4878             width = This->currentDesc.Width;
4879             pitch = IWineD3DSurface_GetPitch(iface);
4880
4881             /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
4882              * but it isn't set (yet) in all cases it is getting called. */
4883             if ((convert != NO_CONVERSION) && (This->Flags & SFLAG_PBO))
4884             {
4885                 struct wined3d_context *context = NULL;
4886
4887                 TRACE("Removing the pbo attached to surface %p\n", This);
4888
4889                 if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4890                 surface_remove_pbo(This);
4891                 if (context) context_release(context);
4892             }
4893
4894             if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
4895                 int height = This->currentDesc.Height;
4896
4897                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4898                 outpitch = width * bpp;
4899                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4900
4901                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4902                 if(!mem) {
4903                     ERR("Out of memory %d, %d!\n", outpitch, height);
4904                     return WINED3DERR_OUTOFVIDEOMEMORY;
4905                 }
4906                 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
4907
4908                 This->Flags |= SFLAG_CONVERTED;
4909             } else {
4910                 This->Flags &= ~SFLAG_CONVERTED;
4911                 mem = This->resource.allocatedMemory;
4912             }
4913
4914             flush_to_framebuffer_drawpixels(This, format, type, bpp, mem);
4915
4916             /* Don't delete PBO memory */
4917             if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
4918                 HeapFree(GetProcessHeap(), 0, mem);
4919         }
4920     } else /* if(flag & (SFLAG_INTEXTURE | SFLAG_INSRGBTEX)) */ {
4921         if (drawable_read_ok && (This->Flags & SFLAG_INDRAWABLE)) {
4922             read_from_framebuffer_texture(This, flag == SFLAG_INSRGBTEX);
4923         }
4924         else
4925         {
4926             /* Upload from system memory */
4927             BOOL srgb = flag == SFLAG_INSRGBTEX;
4928             struct wined3d_context *context = NULL;
4929
4930             d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */,
4931                     &format, &internal, &type, &convert, &bpp, srgb);
4932
4933             if(srgb) {
4934                 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INSYSMEM)) == SFLAG_INTEXTURE) {
4935                     /* Performance warning ... */
4936                     FIXME("%p: Downloading rgb texture to reload it as srgb\n", This);
4937                     IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4938                 }
4939             } else {
4940                 if((This->Flags & (SFLAG_INSRGBTEX | SFLAG_INSYSMEM)) == SFLAG_INSRGBTEX) {
4941                     /* Performance warning ... */
4942                     FIXME("%p: Downloading srgb texture to reload it as rgb\n", This);
4943                     IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4944                 }
4945             }
4946             if(!(This->Flags & SFLAG_INSYSMEM)) {
4947                 /* Should not happen */
4948                 ERR("Trying to load a texture from sysmem, but SFLAG_INSYSMEM is not set\n");
4949                 /* Lets hope we get it from somewhere... */
4950                 IWineD3DSurfaceImpl_LoadLocation(iface, SFLAG_INSYSMEM, rect);
4951             }
4952
4953             if (!device->isInDraw) context = context_acquire(device, NULL, CTXUSAGE_RESOURCELOAD);
4954
4955             surface_prepare_texture(This, srgb);
4956             surface_bind_and_dirtify(This, srgb);
4957
4958             if(This->CKeyFlags & WINEDDSD_CKSRCBLT) {
4959                 This->Flags |= SFLAG_GLCKEY;
4960                 This->glCKey = This->SrcBltCKey;
4961             }
4962             else This->Flags &= ~SFLAG_GLCKEY;
4963
4964             /* The width is in 'length' not in bytes */
4965             width = This->currentDesc.Width;
4966             pitch = IWineD3DSurface_GetPitch(iface);
4967
4968             /* Don't use PBOs for converted surfaces. During PBO conversion we look at SFLAG_CONVERTED
4969              * but it isn't set (yet) in all cases it is getting called. */
4970             if((convert != NO_CONVERSION) && (This->Flags & SFLAG_PBO)) {
4971                 TRACE("Removing the pbo attached to surface %p\n", This);
4972                 surface_remove_pbo(This);
4973             }
4974
4975             if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
4976                 int height = This->currentDesc.Height;
4977
4978                 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
4979                 outpitch = width * bpp;
4980                 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
4981
4982                 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
4983                 if(!mem) {
4984                     ERR("Out of memory %d, %d!\n", outpitch, height);
4985                     if (context) context_release(context);
4986                     return WINED3DERR_OUTOFVIDEOMEMORY;
4987                 }
4988                 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
4989             }
4990             else if (This->resource.format_desc->format == WINED3DFMT_P8_UINT
4991                     && (gl_info->supported[EXT_PALETTED_TEXTURE] || device->blitter->color_fixup_supported(This->resource.format_desc->color_fixup)))
4992             {
4993                 d3dfmt_p8_upload_palette(iface, convert);
4994                 mem = This->resource.allocatedMemory;
4995             } else {
4996                 mem = This->resource.allocatedMemory;
4997             }
4998
4999             /* Make sure the correct pitch is used */
5000             ENTER_GL();
5001             glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
5002             LEAVE_GL();
5003
5004             if (This->Flags & SFLAG_NONPOW2) {
5005                 TRACE("non power of two support\n");
5006                 if (mem || (This->Flags & SFLAG_PBO)) {
5007                     surface_upload_data(This, internal, This->currentDesc.Width, This->currentDesc.Height, format, type, mem);
5008                 }
5009             } else {
5010                 /* When making the realloc conditional, keep in mind that GL_APPLE_client_storage may be in use, and This->resource.allocatedMemory
5011                  * changed. So also keep track of memory changes. In this case the texture has to be reallocated
5012                  */
5013                 if (mem || (This->Flags & SFLAG_PBO)) {
5014                     surface_upload_data(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
5015                 }
5016             }
5017
5018             /* Restore the default pitch */
5019             ENTER_GL();
5020             glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
5021             LEAVE_GL();
5022
5023             if (context) context_release(context);
5024
5025             /* Don't delete PBO memory */
5026             if((mem != This->resource.allocatedMemory) && !(This->Flags & SFLAG_PBO))
5027                 HeapFree(GetProcessHeap(), 0, mem);
5028         }
5029     }
5030
5031     if(rect == NULL) {
5032         This->Flags |= flag;
5033     }
5034
5035     if (in_fbo && (This->Flags & (SFLAG_INTEXTURE | SFLAG_INDRAWABLE))) {
5036         /* With ORM_FBO, SFLAG_INTEXTURE and SFLAG_INDRAWABLE are the same for offscreen targets. */
5037         This->Flags |= (SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
5038     }
5039
5040     return WINED3D_OK;
5041 }
5042
5043 static HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container)
5044 {
5045     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
5046     IWineD3DSwapChain *swapchain = NULL;
5047
5048     /* Update the drawable size method */
5049     if(container) {
5050         IWineD3DBase_QueryInterface(container, &IID_IWineD3DSwapChain, (void **) &swapchain);
5051     }
5052     if(swapchain) {
5053         This->get_drawable_size = get_drawable_size_swapchain;
5054         IWineD3DSwapChain_Release(swapchain);
5055     } else if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5056         switch(wined3d_settings.offscreen_rendering_mode) {
5057             case ORM_FBO:        This->get_drawable_size = get_drawable_size_fbo;        break;
5058             case ORM_BACKBUFFER: This->get_drawable_size = get_drawable_size_backbuffer; break;
5059         }
5060     }
5061
5062     return IWineD3DBaseSurfaceImpl_SetContainer(iface, container);
5063 }
5064
5065 static WINED3DSURFTYPE WINAPI IWineD3DSurfaceImpl_GetImplType(IWineD3DSurface *iface) {
5066     return SURFACE_OPENGL;
5067 }
5068
5069 static HRESULT WINAPI IWineD3DSurfaceImpl_DrawOverlay(IWineD3DSurface *iface) {
5070     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
5071     HRESULT hr;
5072
5073     /* If there's no destination surface there is nothing to do */
5074     if(!This->overlay_dest) return WINED3D_OK;
5075
5076     /* Blt calls ModifyLocation on the dest surface, which in turn calls DrawOverlay to
5077      * update the overlay. Prevent an endless recursion
5078      */
5079     if(This->overlay_dest->Flags & SFLAG_INOVERLAYDRAW) {
5080         return WINED3D_OK;
5081     }
5082     This->overlay_dest->Flags |= SFLAG_INOVERLAYDRAW;
5083     hr = IWineD3DSurfaceImpl_Blt((IWineD3DSurface *) This->overlay_dest, &This->overlay_destrect,
5084                                  iface, &This->overlay_srcrect, WINEDDBLT_WAIT,
5085                                  NULL, WINED3DTEXF_LINEAR);
5086     This->overlay_dest->Flags &= ~SFLAG_INOVERLAYDRAW;
5087
5088     return hr;
5089 }
5090
5091 BOOL surface_is_offscreen(IWineD3DSurface *iface)
5092 {
5093     IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
5094     IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) This->container;
5095
5096     /* Not on a swapchain - must be offscreen */
5097     if (!(This->Flags & SFLAG_SWAPCHAIN)) return TRUE;
5098
5099     /* The front buffer is always onscreen */
5100     if(iface == swapchain->frontBuffer) return FALSE;
5101
5102     /* If the swapchain is rendered to an FBO, the backbuffer is
5103      * offscreen, otherwise onscreen */
5104     return swapchain->render_to_fbo;
5105 }
5106
5107 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
5108 {
5109     /* IUnknown */
5110     IWineD3DBaseSurfaceImpl_QueryInterface,
5111     IWineD3DBaseSurfaceImpl_AddRef,
5112     IWineD3DSurfaceImpl_Release,
5113     /* IWineD3DResource */
5114     IWineD3DBaseSurfaceImpl_GetParent,
5115     IWineD3DBaseSurfaceImpl_SetPrivateData,
5116     IWineD3DBaseSurfaceImpl_GetPrivateData,
5117     IWineD3DBaseSurfaceImpl_FreePrivateData,
5118     IWineD3DBaseSurfaceImpl_SetPriority,
5119     IWineD3DBaseSurfaceImpl_GetPriority,
5120     IWineD3DSurfaceImpl_PreLoad,
5121     IWineD3DSurfaceImpl_UnLoad,
5122     IWineD3DBaseSurfaceImpl_GetType,
5123     /* IWineD3DSurface */
5124     IWineD3DBaseSurfaceImpl_GetContainer,
5125     IWineD3DBaseSurfaceImpl_GetDesc,
5126     IWineD3DSurfaceImpl_LockRect,
5127     IWineD3DSurfaceImpl_UnlockRect,
5128     IWineD3DSurfaceImpl_GetDC,
5129     IWineD3DSurfaceImpl_ReleaseDC,
5130     IWineD3DSurfaceImpl_Flip,
5131     IWineD3DSurfaceImpl_Blt,
5132     IWineD3DBaseSurfaceImpl_GetBltStatus,
5133     IWineD3DBaseSurfaceImpl_GetFlipStatus,
5134     IWineD3DBaseSurfaceImpl_IsLost,
5135     IWineD3DBaseSurfaceImpl_Restore,
5136     IWineD3DSurfaceImpl_BltFast,
5137     IWineD3DBaseSurfaceImpl_GetPalette,
5138     IWineD3DBaseSurfaceImpl_SetPalette,
5139     IWineD3DSurfaceImpl_RealizePalette,
5140     IWineD3DBaseSurfaceImpl_SetColorKey,
5141     IWineD3DBaseSurfaceImpl_GetPitch,
5142     IWineD3DSurfaceImpl_SetMem,
5143     IWineD3DBaseSurfaceImpl_SetOverlayPosition,
5144     IWineD3DBaseSurfaceImpl_GetOverlayPosition,
5145     IWineD3DBaseSurfaceImpl_UpdateOverlayZOrder,
5146     IWineD3DBaseSurfaceImpl_UpdateOverlay,
5147     IWineD3DBaseSurfaceImpl_SetClipper,
5148     IWineD3DBaseSurfaceImpl_GetClipper,
5149     /* Internal use: */
5150     IWineD3DSurfaceImpl_LoadTexture,
5151     IWineD3DSurfaceImpl_BindTexture,
5152     IWineD3DSurfaceImpl_SaveSnapshot,
5153     IWineD3DSurfaceImpl_SetContainer,
5154     IWineD3DBaseSurfaceImpl_GetData,
5155     IWineD3DSurfaceImpl_SetFormat,
5156     IWineD3DSurfaceImpl_PrivateSetup,
5157     IWineD3DSurfaceImpl_ModifyLocation,
5158     IWineD3DSurfaceImpl_LoadLocation,
5159     IWineD3DSurfaceImpl_GetImplType,
5160     IWineD3DSurfaceImpl_DrawOverlay
5161 };
5162 #undef GLINFO_LOCATION
5163
5164 #define GLINFO_LOCATION device->adapter->gl_info
5165 static HRESULT ffp_blit_alloc(IWineD3DDevice *iface) { return WINED3D_OK; }
5166 /* Context activation is done by the caller. */
5167 static void ffp_blit_free(IWineD3DDevice *iface) { }
5168
5169 /* Context activation is done by the caller. */
5170 static HRESULT ffp_blit_set(IWineD3DDevice *iface, const struct GlPixelFormatDesc *format_desc,
5171         GLenum textype, UINT width, UINT height)
5172 {
5173     ENTER_GL();
5174     glEnable(textype);
5175     checkGLcall("glEnable(textype)");
5176     LEAVE_GL();
5177     return WINED3D_OK;
5178 }
5179
5180 /* Context activation is done by the caller. */
5181 static void ffp_blit_unset(IWineD3DDevice *iface)
5182 {
5183     IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) iface;
5184     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
5185
5186     ENTER_GL();
5187     glDisable(GL_TEXTURE_2D);
5188     checkGLcall("glDisable(GL_TEXTURE_2D)");
5189     if (gl_info->supported[ARB_TEXTURE_CUBE_MAP])
5190     {
5191         glDisable(GL_TEXTURE_CUBE_MAP_ARB);
5192         checkGLcall("glDisable(GL_TEXTURE_CUBE_MAP_ARB)");
5193     }
5194     if (gl_info->supported[ARB_TEXTURE_RECTANGLE])
5195     {
5196         glDisable(GL_TEXTURE_RECTANGLE_ARB);
5197         checkGLcall("glDisable(GL_TEXTURE_RECTANGLE_ARB)");
5198     }
5199     LEAVE_GL();
5200 }
5201
5202 static BOOL ffp_blit_color_fixup_supported(struct color_fixup_desc fixup)
5203 {
5204     if (TRACE_ON(d3d_surface) && TRACE_ON(d3d))
5205     {
5206         TRACE("Checking support for fixup:\n");
5207         dump_color_fixup_desc(fixup);
5208     }
5209
5210     /* We only support identity conversions. */
5211     if (is_identity_fixup(fixup))
5212     {
5213         TRACE("[OK]\n");
5214         return TRUE;
5215     }
5216
5217     TRACE("[FAILED]\n");
5218     return FALSE;
5219 }
5220
5221 const struct blit_shader ffp_blit =  {
5222     ffp_blit_alloc,
5223     ffp_blit_free,
5224     ffp_blit_set,
5225     ffp_blit_unset,
5226     ffp_blit_color_fixup_supported
5227 };