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