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