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