wined3d: Allow SetCursorProperties on existing cursor.
[wine/multimedia.git] / dlls / wined3d / surface.c
blob30ae169fe06749a47ba93506e9a6500541458b6f
1 /*
2 * IWineD3DSurface Implementation
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 Stefan Dösinger for CodeWeavers
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include "wine/port.h"
29 #include "wined3d_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
32 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
34 typedef enum {
35 NO_CONVERSION,
36 CONVERT_PALETTED,
37 CONVERT_PALETTED_CK,
38 CONVERT_CK_565,
39 CONVERT_CK_5551,
40 CONVERT_CK_4444,
41 CONVERT_CK_4444_ARGB,
42 CONVERT_CK_1555,
43 CONVERT_555,
44 CONVERT_CK_RGB24,
45 CONVERT_CK_8888,
46 CONVERT_CK_8888_ARGB,
47 CONVERT_RGB32_888,
48 CONVERT_V8U8
49 } CONVERT_TYPES;
51 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf);
53 static void surface_download_data(IWineD3DSurfaceImpl *This) {
54 if (This->resource.format == WINED3DFMT_DXT1 ||
55 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
56 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
57 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* We can assume this as the texture would not have been created otherwise */
58 FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
59 } else {
60 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
61 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
63 ENTER_GL();
65 GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory));
66 checkGLcall("glGetCompressedTexImageARB()");
68 LEAVE_GL();
70 } else {
71 void *mem;
72 int src_pitch = 0;
73 int dst_pitch = 0;
75 if(This->Flags & SFLAG_CONVERTED) {
76 FIXME("Read back converted textures unsupported\n");
77 return;
80 if (This->Flags & SFLAG_NONPOW2) {
81 src_pitch = This->bytesPerPixel * This->pow2Width;
82 dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
83 src_pitch = (src_pitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
84 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
85 } else {
86 mem = This->resource.allocatedMemory;
89 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
90 This->glDescription.glFormat, This->glDescription.glType, mem);
92 ENTER_GL();
94 glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
95 This->glDescription.glType, mem);
96 checkGLcall("glGetTexImage()");
98 LEAVE_GL();
100 if (This->Flags & SFLAG_NONPOW2) {
101 LPBYTE src_data, dst_data;
102 int y;
104 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
105 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
106 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
108 * We're doing this...
110 * instead of boxing the texture :
111 * |<-texture width ->| -->pow2width| /\
112 * |111111111111111111| | |
113 * |222 Texture 222222| boxed empty | texture height
114 * |3333 Data 33333333| | |
115 * |444444444444444444| | \/
116 * ----------------------------------- |
117 * | boxed empty | boxed empty | pow2height
118 * | | | \/
119 * -----------------------------------
122 * we're repacking the data to the expected texture width
124 * |<-texture width ->| -->pow2width| /\
125 * |111111111111111111222222222222222| |
126 * |222333333333333333333444444444444| texture height
127 * |444444 | |
128 * | | \/
129 * | | |
130 * | empty | pow2height
131 * | | \/
132 * -----------------------------------
134 * == is the same as
136 * |<-texture width ->| /\
137 * |111111111111111111|
138 * |222222222222222222|texture height
139 * |333333333333333333|
140 * |444444444444444444| \/
141 * --------------------
143 * this also means that any references to allocatedMemory should work with the data as if were a
144 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
146 * internally the texture is still stored in a boxed format so any references to textureName will
147 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
149 * Performance should not be an issue, because applications normally do not lock the surfaces when
150 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
151 * and doesn't have to be re-read.
153 src_data = mem;
154 dst_data = This->resource.allocatedMemory;
155 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
156 for (y = 1 ; y < This->currentDesc.Height; y++) {
157 /* skip the first row */
158 src_data += src_pitch;
159 dst_data += dst_pitch;
160 memcpy(dst_data, src_data, dst_pitch);
163 HeapFree(GetProcessHeap(), 0, mem);
168 static void surface_upload_data(IWineD3DSurfaceImpl *This, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data) {
169 if (This->resource.format == WINED3DFMT_DXT1 ||
170 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
171 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
172 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
173 FIXME("Using DXT1/3/5 without advertized support\n");
174 } else {
175 TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data);
176 ENTER_GL();
177 /* glCompressedTexSubImage2D for uploading and glTexImage2D for allocating does not work well on some drivers(r200 dri, MacOS ATI driver)
178 * glCompressedTexImage2D does not accept NULL pointers. So for compressed textures surface_allocate_surface does nothing, and this
179 * function uses glCompressedTexImage2D instead of the SubImage call
181 GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, This->glDescription.glFormatInternal,
182 width, height, 0 /* border */, This->resource.size, data));
183 checkGLcall("glCompressedTexSubImage2D");
184 LEAVE_GL();
186 } else {
187 TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This, width, height, data);
188 ENTER_GL();
189 glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data);
190 checkGLcall("glTexSubImage2D");
191 LEAVE_GL();
195 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) {
196 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,
197 This->glDescription.target, This->glDescription.level, debug_d3dformat(This->resource.format), internal, width, height, format, type);
199 if (This->resource.format == WINED3DFMT_DXT1 ||
200 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
201 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
202 /* glCompressedTexImage2D does not accept NULL pointers, so we cannot allocate a compressed texture without uploading data */
203 TRACE("Not allocating compressed surfaces, surface_upload_data will specify them\n");
204 return;
207 ENTER_GL();
209 glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, NULL);
210 checkGLcall("glTexImage2D");
212 LEAVE_GL();
215 /* *******************************************
216 IWineD3DSurface IUnknown parts follow
217 ******************************************* */
218 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
220 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
221 /* Warn ,but be nice about things */
222 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
224 if (IsEqualGUID(riid, &IID_IUnknown)
225 || IsEqualGUID(riid, &IID_IWineD3DBase)
226 || IsEqualGUID(riid, &IID_IWineD3DResource)
227 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
228 IUnknown_AddRef((IUnknown*)iface);
229 *ppobj = This;
230 return S_OK;
232 *ppobj = NULL;
233 return E_NOINTERFACE;
236 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
237 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
238 ULONG ref = InterlockedIncrement(&This->resource.ref);
239 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
240 return ref;
243 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
244 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
245 ULONG ref = InterlockedDecrement(&This->resource.ref);
246 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
247 if (ref == 0) {
248 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
249 TRACE("(%p) : cleaning up\n", This);
251 if(iface == device->lastActiveRenderTarget) {
252 IWineD3DSwapChainImpl *swapchain = device->swapchains ? (IWineD3DSwapChainImpl *) device->swapchains[0] : NULL;
254 TRACE("Last active render target destroyed\n");
255 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
256 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
257 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
258 * and the lastActiveRenderTarget member shouldn't matter
260 if(swapchain) {
261 if(swapchain->backBuffer && swapchain->backBuffer[0] != iface) {
262 TRACE("Activating primary back buffer\n");
263 ActivateContext(device, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
264 } else if(!swapchain->backBuffer && swapchain->frontBuffer != iface) {
265 /* Single buffering environment */
266 TRACE("Activating primary front buffer\n");
267 ActivateContext(device, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
268 } else {
269 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
270 /* Implicit render target destroyed, that means the device is being destroyed
271 * whatever we set here, it shouldn't matter
273 device->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
275 } else {
276 /* May happen during ddraw uninitialization */
277 TRACE("Render target set, but swapchain does not exist!\n");
278 device->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
282 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
283 ENTER_GL();
284 TRACE("Deleting texture %d\n", This->glDescription.textureName);
285 glDeleteTextures(1, &This->glDescription.textureName);
286 LEAVE_GL();
289 if(This->Flags & SFLAG_DIBSECTION) {
290 /* Release the DC */
291 SelectObject(This->hDC, This->dib.holdbitmap);
292 DeleteDC(This->hDC);
293 /* Release the DIB section */
294 DeleteObject(This->dib.DIBsection);
295 This->dib.bitmap_data = NULL;
296 This->resource.allocatedMemory = NULL;
298 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
300 HeapFree(GetProcessHeap(), 0, This->palette9);
302 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
303 if(iface == device->ddraw_primary)
304 device->ddraw_primary = NULL;
306 TRACE("(%p) Released\n", This);
307 HeapFree(GetProcessHeap(), 0, This);
310 return ref;
313 /* ****************************************************
314 IWineD3DSurface IWineD3DResource parts follow
315 **************************************************** */
316 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
317 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
320 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
321 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
324 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
325 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
328 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
329 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
332 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
333 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
336 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
337 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
340 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
341 /* TODO: re-write the way textures and managed,
342 * use a 'opengl context manager' to manage RenderTarget surfaces
343 ** *********************************************************/
345 /* TODO: check for locks */
346 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
347 IWineD3DBaseTexture *baseTexture = NULL;
348 TRACE("(%p)Checking to see if the container is a base texture\n", This);
349 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
350 TRACE("Passing to conatiner\n");
351 IWineD3DBaseTexture_PreLoad(baseTexture);
352 IWineD3DBaseTexture_Release(baseTexture);
353 } else {
354 TRACE("(%p) : About to load surface\n", This);
355 ENTER_GL();
356 #if 0 /* TODO: context manager support */
357 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
358 #endif
359 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
360 if (!This->glDescription.level) {
361 if (!This->glDescription.textureName) {
362 glGenTextures(1, &This->glDescription.textureName);
363 checkGLcall("glGenTextures");
364 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
366 glBindTexture(This->glDescription.target, This->glDescription.textureName);
367 checkGLcall("glBindTexture");
368 IWineD3DSurface_LoadTexture(iface);
369 /* This is where we should be reducing the amount of GLMemoryUsed */
370 } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
371 /* assume this is a coding error not a real error for now */
372 FIXME("Mipmap surface has a glTexture bound to it!\n");
374 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
375 /* Tell opengl to try and keep this texture in video ram (well mostly) */
376 GLclampf tmp;
377 tmp = 0.9f;
378 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
380 /* TODO: disable texture support, if it wastn't enabled when we entered. */
381 #if 0 /* TODO: context manager support */
382 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
383 /* we don't care when the state is disabled(if atall) */);
384 #endif
385 LEAVE_GL();
387 return;
390 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
391 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
392 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
395 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
396 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
397 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
400 /* ******************************************************
401 IWineD3DSurface IWineD3DSurface parts follow
402 ****************************************************** */
404 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
405 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
406 IWineD3DBase *container = 0;
408 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
410 if (!ppContainer) {
411 ERR("Called without a valid ppContainer.\n");
414 /** From MSDN:
415 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
416 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
417 * GetContainer will return the Direct3D device used to create the surface.
419 if (This->container) {
420 container = This->container;
421 } else {
422 container = (IWineD3DBase *)This->resource.wineD3DDevice;
425 TRACE("Relaying to QueryInterface\n");
426 return IUnknown_QueryInterface(container, riid, ppContainer);
429 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
430 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
432 TRACE("(%p) : copying into %p\n", This, pDesc);
433 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
434 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
435 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
436 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
437 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
438 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
439 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
440 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
441 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
442 return WINED3D_OK;
445 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
446 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
447 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
448 if (This->glDescription.textureName == 0 && textureName != 0) {
449 This->Flags &= ~SFLAG_INTEXTURE;
450 IWineD3DSurface_AddDirtyRect(iface, NULL);
452 This->glDescription.textureName = textureName;
453 This->glDescription.target = target;
456 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
457 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
458 TRACE("(%p) : returning %p\n", This, &This->glDescription);
459 *glDescription = &This->glDescription;
462 /* TODO: think about moving this down to resource? */
463 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
464 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
465 /* 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 futture */
466 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
467 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
469 return (CONST void*)(This->resource.allocatedMemory);
472 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch, BOOL srcUpsideDown) {
473 BYTE *mem;
474 GLint fmt;
475 GLint type;
476 BYTE *row, *top, *bottom;
477 int i;
478 BOOL bpp;
480 switch(This->resource.format)
482 case WINED3DFMT_P8:
484 /* GL can't return palettized data, so read ARGB pixels into a
485 * separate block of memory and convert them into palettized format
486 * in software. Slow, but if the app means to use palettized render
487 * targets and locks it...
489 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
490 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
491 * for the color channels when palettizing the colors.
493 fmt = GL_RGB;
494 type = GL_UNSIGNED_BYTE;
495 pitch *= 3;
496 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
497 if(!mem) {
498 ERR("Out of memory\n");
499 return;
501 bpp = This->bytesPerPixel * 3;
503 break;
505 default:
506 mem = dest;
507 fmt = This->glDescription.glFormat;
508 type = This->glDescription.glType;
509 bpp = This->bytesPerPixel;
512 glReadPixels(rect->left, rect->top,
513 rect->right - rect->left,
514 rect->bottom - rect->top,
515 fmt, type, mem);
516 vcheckGLcall("glReadPixels");
518 /* TODO: Merge this with the palettization loop below for P8 targets */
520 if(!srcUpsideDown) {
521 UINT len, off;
522 /* glReadPixels returns the image upside down, and there is no way to prevent this.
523 Flip the lines in software */
524 len = (rect->right - rect->left) * bpp;
525 off = rect->left * bpp;
527 row = HeapAlloc(GetProcessHeap(), 0, len);
528 if(!row) {
529 ERR("Out of memory\n");
530 if(This->resource.format == WINED3DFMT_P8) HeapFree(GetProcessHeap(), 0, mem);
531 return;
534 top = mem + pitch * rect->top;
535 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
536 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
537 memcpy(row, top + off, len);
538 memcpy(top + off, bottom + off, len);
539 memcpy(bottom + off, row, len);
540 top += pitch;
541 bottom -= pitch;
543 HeapFree(GetProcessHeap(), 0, row);
546 if(This->resource.format == WINED3DFMT_P8) {
547 PALETTEENTRY *pal;
548 DWORD width = pitch / 3;
549 int x, y, c;
550 if(This->palette) {
551 pal = This->palette->palents;
552 } else {
553 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
556 for(y = rect->top; y < rect->bottom; y++) {
557 for(x = rect->left; x < rect->right; x++) {
558 /* start lines pixels */
559 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
560 BYTE *green = blue + 1;
561 BYTE *red = green + 1;
563 for(c = 0; c < 256; c++) {
564 if(*red == pal[c].peRed &&
565 *green == pal[c].peGreen &&
566 *blue == pal[c].peBlue)
568 *((BYTE *) dest + y * width + x) = c;
569 break;
574 HeapFree(GetProcessHeap(), 0, mem);
578 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
579 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
580 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
581 IWineD3DSwapChainImpl *swapchain = NULL;
583 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
585 if (!(This->Flags & SFLAG_LOCKABLE)) {
586 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
587 texture regions, and since the destination is an unlockable region we need
588 to tolerate this */
589 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
590 /*return WINED3DERR_INVALIDCALL; */
593 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
595 /* Mark the surface locked */
596 This->Flags |= SFLAG_LOCKED;
598 /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy */
599 if(!This->resource.allocatedMemory) {
600 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + 4);
601 This->Flags &= ~SFLAG_INSYSMEM; /* This is the marker that surface data has to be downloaded */
604 /* Calculate the correct start address to report */
605 if (NULL == pRect) {
606 pLockedRect->pBits = This->resource.allocatedMemory;
607 This->lockedRect.left = 0;
608 This->lockedRect.top = 0;
609 This->lockedRect.right = This->currentDesc.Width;
610 This->lockedRect.bottom = This->currentDesc.Height;
611 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
612 } else {
613 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
615 if ((pRect->top < 0) ||
616 (pRect->left < 0) ||
617 (pRect->left >= pRect->right) ||
618 (pRect->top >= pRect->bottom) ||
619 (pRect->right > This->currentDesc.Width) ||
620 (pRect->bottom > This->currentDesc.Height))
622 WARN(" Invalid values in pRect !!!\n");
623 return WINED3DERR_INVALIDCALL;
626 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
627 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
628 } else {
629 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
631 This->lockedRect.left = pRect->left;
632 This->lockedRect.top = pRect->top;
633 This->lockedRect.right = pRect->right;
634 This->lockedRect.bottom = pRect->bottom;
637 if (This->Flags & SFLAG_NONPOW2) {
638 TRACE("Locking non-power 2 texture\n");
641 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
642 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
643 * changed
645 if(!(This->Flags & SFLAG_DYNLOCK)) {
646 This->lockCount++;
647 /* MAXLOCKCOUNT is defined in wined3d_private.h */
648 if(This->lockCount > MAXLOCKCOUNT) {
649 TRACE("Surface is locked regularily, not freeing the system memory copy any more\n");
650 This->Flags |= SFLAG_DYNLOCK;
654 if((Flags & WINED3DLOCK_DISCARD) || (This->Flags & SFLAG_INSYSMEM)) {
655 TRACE("WINED3DLOCK_DISCARD flag passed, or local copy is up to date, not downloading data\n");
656 goto lock_end;
659 /* Now download the surface content from opengl
660 * Use the render target readback if the surface is on a swapchain(=onscreen render target) or the current primary target
661 * Offscreen targets which are not active at the moment or are higher targets(fbos) can be locked with the texture path
663 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
664 if(swapchain || iface == myDevice->render_targets[0]) {
665 BOOL srcIsUpsideDown;
667 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
668 static BOOL warned = FALSE;
669 if(!warned) {
670 ERR("The application tries to lock the render target, but render target locking is disabled\n");
671 warned = TRUE;
673 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
674 return WINED3D_OK;
677 /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
678 * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
679 * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
680 * context->last_was_blit set on the unlock.
682 ENTER_GL();
683 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
685 /* Select the correct read buffer, and give some debug output.
686 * There is no need to keep track of the current read buffer or reset it, every part of the code
687 * that reads sets the read buffer as desired.
689 if(!swapchain) {
690 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
691 * Read from the back buffer
693 TRACE("Locking offscreen render target\n");
694 glReadBuffer(myDevice->offscreenBuffer);
695 srcIsUpsideDown = TRUE;
696 } else {
697 if(iface == swapchain->frontBuffer) {
698 TRACE("Locking the front buffer\n");
699 glReadBuffer(GL_FRONT);
700 } else if(swapchain->backBuffer && iface == swapchain->backBuffer[0]) {
701 TRACE("Locking the back buffer\n");
702 glReadBuffer(GL_BACK);
703 } else {
704 /* Ok, there is an issue: OpenGL does not guarant any back buffer number, so all we can do is to read GL_BACK
705 * and hope it gives what the app wants
707 FIXME("Application is locking a 2nd or higher back buffer\n");
708 glReadBuffer(GL_BACK);
710 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
711 srcIsUpsideDown = FALSE;
714 switch(wined3d_settings.rendertargetlock_mode) {
715 case RTL_AUTO:
716 case RTL_READDRAW:
717 case RTL_READTEX:
718 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
719 break;
721 case RTL_TEXDRAW:
722 case RTL_TEXTEX:
723 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
724 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
725 break;
727 LEAVE_GL();
729 /* Mark the local copy up to date if a full download was done */
730 if(This->lockedRect.left == 0 &&
731 This->lockedRect.top == 0 &&
732 This->lockedRect.right == This->currentDesc.Width &&
733 This->lockedRect.bottom == This->currentDesc.Height) {
734 This->Flags |= SFLAG_INSYSMEM;
736 } else if(iface == myDevice->stencilBufferTarget) {
737 /** the depth stencil in openGL has a format of GL_FLOAT
738 * which should be good for WINED3DFMT_D16_LOCKABLE
739 * and WINED3DFMT_D16
740 * it is unclear what format the stencil buffer is in except.
741 * 'Each index is converted to fixed point...
742 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
743 * mappings in the table GL_PIXEL_MAP_S_TO_S.
744 * glReadPixels(This->lockedRect.left,
745 * This->lockedRect.bottom - j - 1,
746 * This->lockedRect.right - This->lockedRect.left,
747 * 1,
748 * GL_DEPTH_COMPONENT,
749 * type,
750 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
752 * Depth Stencil surfaces which are not the current depth stencil target should have their data in a
753 * gl texture(next path), or in local memory(early return because of set SFLAG_INSYSMEM above). If
754 * none of that is the case the problem is not in this function :-)
755 ********************************************/
756 FIXME("Depth stencil locking not supported yet\n");
757 } else {
758 /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */
759 TRACE("locking an ordinarary surface\n");
761 /* TODO: Make sure that *any* context is active for this thread. It is not important which context that is,
762 * nor that is has any special setup(CTXUSAGE_LOADRESOURCE is fine), but the code below needs a context.
763 * A context is guaranteed to be there in a single threaded environment, but not with multithreading
765 if (0 != This->glDescription.textureName) {
766 /* Now I have to copy thing bits back */
768 /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
769 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
770 ENTER_GL();
771 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
772 checkGLcall("glActiveTextureARB");
773 LEAVE_GL();
775 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
776 IWineD3DSurface_PreLoad(iface);
778 surface_download_data(This);
781 /* The local copy is now up to date to the opengl one because a full download was done */
782 This->Flags |= SFLAG_INSYSMEM;
785 lock_end:
786 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
787 /* Don't dirtify */
788 } else {
789 IWineD3DBaseTexture *pBaseTexture;
791 * Dirtify on lock
792 * as seen in msdn docs
794 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
796 /** Dirtify Container if needed */
797 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
798 TRACE("Making container dirty\n");
799 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
800 IWineD3DBaseTexture_Release(pBaseTexture);
801 } else {
802 TRACE("Surface is standalone, no need to dirty the container\n");
806 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch,
807 This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
808 return WINED3D_OK;
811 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
812 GLint prev_store;
813 GLint prev_rasterpos[4];
814 GLint skipBytes = 0;
815 BOOL storechanged = FALSE, memory_allocated = FALSE;
816 GLint fmt, type;
817 BYTE *mem;
818 UINT bpp;
819 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
821 glDisable(GL_TEXTURE_2D);
822 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
824 glFlush();
825 vcheckGLcall("glFlush");
826 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
827 vcheckGLcall("glIntegerv");
828 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
829 vcheckGLcall("glIntegerv");
830 glPixelZoom(1.0, -1.0);
831 vcheckGLcall("glPixelZoom");
833 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
834 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
835 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
837 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
838 vcheckGLcall("glRasterPos2f");
840 /* Some drivers(radeon dri, others?) don't like exceptions during
841 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
842 * after ReleaseDC. Reading it will cause an exception, which x11drv will
843 * catch to put the dib section in InSync mode, which leads to a crash
844 * and a blocked x server on my radeon card.
846 * The following lines read the dib section so it is put in inSync mode
847 * before glDrawPixels is called and the crash is prevented. There won't
848 * be any interfering gdi accesses, because UnlockRect is called from
849 * ReleaseDC, and the app won't use the dc any more afterwards.
851 if(This->Flags & SFLAG_DIBSECTION) {
852 volatile BYTE read;
853 read = This->resource.allocatedMemory[0];
856 switch (This->resource.format) {
857 /* No special care needed */
858 case WINED3DFMT_A4R4G4B4:
859 case WINED3DFMT_R5G6B5:
860 case WINED3DFMT_A1R5G5B5:
861 case WINED3DFMT_R8G8B8:
862 type = This->glDescription.glType;
863 fmt = This->glDescription.glFormat;
864 mem = This->resource.allocatedMemory;
865 bpp = This->bytesPerPixel;
866 break;
868 case WINED3DFMT_X4R4G4B4:
870 int size;
871 unsigned short *data;
872 data = (unsigned short *)This->resource.allocatedMemory;
873 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
874 while(size > 0) {
875 *data |= 0xF000;
876 data++;
877 size--;
879 type = This->glDescription.glType;
880 fmt = This->glDescription.glFormat;
881 mem = This->resource.allocatedMemory;
882 bpp = This->bytesPerPixel;
884 break;
886 case WINED3DFMT_X1R5G5B5:
888 int size;
889 unsigned short *data;
890 data = (unsigned short *)This->resource.allocatedMemory;
891 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
892 while(size > 0) {
893 *data |= 0x8000;
894 data++;
895 size--;
897 type = This->glDescription.glType;
898 fmt = This->glDescription.glFormat;
899 mem = This->resource.allocatedMemory;
900 bpp = This->bytesPerPixel;
902 break;
904 case WINED3DFMT_X8R8G8B8:
906 /* make sure the X byte is set to alpha on, since it
907 could be any random value. This fixes the intro movie in Pirates! */
908 int size;
909 unsigned int *data;
910 data = (unsigned int *)This->resource.allocatedMemory;
911 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
912 while(size > 0) {
913 *data |= 0xFF000000;
914 data++;
915 size--;
918 /* Fall through */
920 case WINED3DFMT_A8R8G8B8:
922 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
923 vcheckGLcall("glPixelStorei");
924 storechanged = TRUE;
925 type = This->glDescription.glType;
926 fmt = This->glDescription.glFormat;
927 mem = This->resource.allocatedMemory;
928 bpp = This->bytesPerPixel;
930 break;
932 case WINED3DFMT_A2R10G10B10:
934 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
935 vcheckGLcall("glPixelStorei");
936 storechanged = TRUE;
937 type = This->glDescription.glType;
938 fmt = This->glDescription.glFormat;
939 mem = This->resource.allocatedMemory;
940 bpp = This->bytesPerPixel;
942 break;
944 case WINED3DFMT_P8:
946 int height = This->glRect.bottom - This->glRect.top;
947 type = GL_UNSIGNED_BYTE;
948 fmt = GL_RGBA;
950 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
951 if(!mem) {
952 ERR("Out of memory\n");
953 return;
955 memory_allocated = TRUE;
956 d3dfmt_convert_surface(This->resource.allocatedMemory,
957 mem,
958 pitch,
959 pitch,
960 height,
961 pitch * 4,
962 CONVERT_PALETTED,
963 This);
964 bpp = This->bytesPerPixel * 4;
965 pitch *= 4;
967 break;
969 default:
970 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
972 /* Give it a try */
973 type = This->glDescription.glType;
974 fmt = This->glDescription.glFormat;
975 mem = This->resource.allocatedMemory;
976 bpp = This->bytesPerPixel;
979 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
980 (This->lockedRect.bottom - This->lockedRect.top)-1,
981 fmt, type,
982 mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
983 checkGLcall("glDrawPixels");
984 glPixelZoom(1.0,1.0);
985 vcheckGLcall("glPixelZoom");
987 glRasterPos3iv(&prev_rasterpos[0]);
988 vcheckGLcall("glRasterPos3iv");
990 /* Reset to previous pack row length */
991 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
992 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
993 if(storechanged) {
994 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
995 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
998 /* Blitting environment requires that 2D texturing is enabled. It was turned off before,
999 * turn it on again
1001 glEnable(GL_TEXTURE_2D);
1002 checkGLcall("glEnable(GL_TEXTURE_2D)");
1004 if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem);
1005 return;
1008 static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) {
1009 float glTexCoord[4];
1011 glTexCoord[0] = (float) This->lockedRect.left / (float) This->pow2Width; /* left */
1012 glTexCoord[1] = (float) This->lockedRect.right / (float) This->pow2Width; /* right */
1013 glTexCoord[2] = (float) This->lockedRect.top / (float) This->pow2Height; /* top */
1014 glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */
1016 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
1018 ENTER_GL();
1020 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1021 checkGLcall("glEnable glBindTexture");
1023 /* No filtering for blts */
1024 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1025 checkGLcall("glTexParameteri");
1026 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1027 checkGLcall("glTexParameteri");
1029 /* Start drawing a quad */
1030 glBegin(GL_QUADS);
1032 glColor3d(1.0f, 1.0f, 1.0f);
1033 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1034 glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0);
1036 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1037 glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0);
1039 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1040 glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0);
1042 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1043 glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0);
1045 glEnd();
1046 checkGLcall("glEnd");
1048 /* Unbind the texture */
1049 glBindTexture(GL_TEXTURE_2D, 0);
1050 checkGLcall("glEnable glBindTexture");
1052 LEAVE_GL();
1055 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1056 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1057 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1058 IWineD3DSwapChainImpl *swapchain = NULL;
1060 if (!(This->Flags & SFLAG_LOCKED)) {
1061 WARN("trying to Unlock an unlocked surf@%p\n", This);
1062 return WINED3DERR_INVALIDCALL;
1065 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1067 if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
1068 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1069 goto unlock_end;
1072 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1073 if(swapchain || iface == myDevice->render_targets[0]) {
1074 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1075 static BOOL warned = FALSE;
1076 if(!warned) {
1077 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1078 warned = TRUE;
1080 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1081 goto unlock_end;
1084 /* Activate the correct context for the render target */
1085 ENTER_GL();
1086 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
1088 if(!swapchain) {
1089 /* Primary offscreen render target */
1090 TRACE("Offscreen render target\n");
1091 glDrawBuffer(myDevice->offscreenBuffer);
1092 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1093 } else {
1094 if(iface == swapchain->frontBuffer) {
1095 TRACE("Onscreen front buffer\n");
1096 glDrawBuffer(GL_FRONT);
1097 checkGLcall("glDrawBuffer(GL_FRONT)");
1098 } else if(iface == swapchain->backBuffer[0]) {
1099 TRACE("Onscreen back buffer\n");
1100 glDrawBuffer(GL_BACK);
1101 checkGLcall("glDrawBuffer(GL_BACK)");
1102 } else {
1103 FIXME("Unlocking a higher back buffer\n");
1104 glDrawBuffer(GL_BACK);
1105 checkGLcall("glDrawBuffer(GL_BACK)");
1107 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1110 switch(wined3d_settings.rendertargetlock_mode) {
1111 case RTL_AUTO:
1112 case RTL_READDRAW:
1113 case RTL_TEXDRAW:
1114 flush_to_framebuffer_drawpixels(This);
1115 break;
1117 case RTL_READTEX:
1118 case RTL_TEXTEX:
1119 flush_to_framebuffer_texture(This);
1120 break;
1122 if(!swapchain) {
1123 glDrawBuffer(myDevice->offscreenBuffer);
1124 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1125 } else if(swapchain->backBuffer) {
1126 glDrawBuffer(GL_BACK);
1127 checkGLcall("glDrawBuffer(GL_BACK)");
1128 } else {
1129 glDrawBuffer(GL_FRONT);
1130 checkGLcall("glDrawBuffer(GL_FRONT)");
1132 LEAVE_GL();
1134 This->dirtyRect.left = This->currentDesc.Width;
1135 This->dirtyRect.top = This->currentDesc.Height;
1136 This->dirtyRect.right = 0;
1137 This->dirtyRect.bottom = 0;
1138 This->Flags |= SFLAG_INDRAWABLE;
1139 } else if(iface == myDevice->stencilBufferTarget) {
1140 FIXME("Depth Stencil buffer locking is not implemented\n");
1141 } else {
1142 /* The rest should be a normal texture */
1143 IWineD3DBaseTextureImpl *impl;
1144 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1145 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1146 * states need resetting
1148 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1149 if(impl->baseTexture.bindCount) {
1150 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1152 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1156 unlock_end:
1157 This->Flags &= ~SFLAG_LOCKED;
1158 memset(&This->lockedRect, 0, sizeof(RECT));
1159 return WINED3D_OK;
1162 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1163 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1164 WINED3DLOCKED_RECT lock;
1165 UINT usage;
1166 BITMAPINFO* b_info;
1167 HDC ddc;
1168 DWORD *masks;
1169 HRESULT hr;
1170 RGBQUAD col[256];
1171 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1173 TRACE("(%p)->(%p)\n",This,pHDC);
1175 if(This->Flags & SFLAG_USERPTR) {
1176 ERR("Not supported on surfaces with an application-provided surfaces\n");
1177 return DDERR_NODC;
1180 /* Give more detailed info for ddraw */
1181 if (This->Flags & SFLAG_DCINUSE)
1182 return DDERR_DCALREADYCREATED;
1184 /* Can't GetDC if the surface is locked */
1185 if (This->Flags & SFLAG_LOCKED)
1186 return WINED3DERR_INVALIDCALL;
1188 memset(&lock, 0, sizeof(lock)); /* To be sure */
1190 /* Create a DIB section if there isn't a hdc yet */
1191 if(!This->hDC) {
1192 int extraline = 0;
1193 SYSTEM_INFO sysInfo;
1195 switch (This->bytesPerPixel) {
1196 case 2:
1197 case 4:
1198 /* Allocate extra space to store the RGB bit masks. */
1199 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1200 break;
1202 case 3:
1203 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1204 break;
1206 default:
1207 /* Allocate extra space for a palette. */
1208 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1209 sizeof(BITMAPINFOHEADER)
1210 + sizeof(RGBQUAD)
1211 * (1 << (This->bytesPerPixel * 8)));
1212 break;
1215 if (!b_info)
1216 return E_OUTOFMEMORY;
1218 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1219 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1220 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1221 * add an extra line to the dib section
1223 GetSystemInfo(&sysInfo);
1224 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1225 extraline = 1;
1226 TRACE("Adding an extra line to the dib section\n");
1229 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1230 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1231 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1232 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1233 b_info->bmiHeader.biPlanes = 1;
1234 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1236 b_info->bmiHeader.biXPelsPerMeter = 0;
1237 b_info->bmiHeader.biYPelsPerMeter = 0;
1238 b_info->bmiHeader.biClrUsed = 0;
1239 b_info->bmiHeader.biClrImportant = 0;
1241 /* Get the bit masks */
1242 masks = (DWORD *) &(b_info->bmiColors);
1243 switch (This->resource.format) {
1244 case WINED3DFMT_R8G8B8:
1245 usage = DIB_RGB_COLORS;
1246 b_info->bmiHeader.biCompression = BI_RGB;
1247 break;
1249 case WINED3DFMT_X1R5G5B5:
1250 case WINED3DFMT_A1R5G5B5:
1251 case WINED3DFMT_A4R4G4B4:
1252 case WINED3DFMT_X4R4G4B4:
1253 case WINED3DFMT_R3G3B2:
1254 case WINED3DFMT_A8R3G3B2:
1255 case WINED3DFMT_A2B10G10R10:
1256 case WINED3DFMT_A8B8G8R8:
1257 case WINED3DFMT_X8B8G8R8:
1258 case WINED3DFMT_A2R10G10B10:
1259 case WINED3DFMT_R5G6B5:
1260 case WINED3DFMT_A16B16G16R16:
1261 usage = 0;
1262 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1263 masks[0] = formatEntry->redMask;
1264 masks[1] = formatEntry->greenMask;
1265 masks[2] = formatEntry->blueMask;
1266 break;
1268 default:
1269 /* Don't know palette */
1270 b_info->bmiHeader.biCompression = BI_RGB;
1271 usage = 0;
1272 break;
1275 ddc = GetDC(0);
1276 if (ddc == 0) {
1277 HeapFree(GetProcessHeap(), 0, b_info);
1278 return HRESULT_FROM_WIN32(GetLastError());
1281 TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
1282 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1283 ReleaseDC(0, ddc);
1285 if (!This->dib.DIBsection) {
1286 ERR("CreateDIBSection failed!\n");
1287 HeapFree(GetProcessHeap(), 0, b_info);
1288 return HRESULT_FROM_WIN32(GetLastError());
1291 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1293 /* copy the existing surface to the dib section */
1294 if(This->resource.allocatedMemory) {
1295 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1296 /* We won't need that any more */
1297 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1298 } else {
1299 /* This is to make LockRect read the gl Texture although memory is allocated */
1300 This->Flags &= ~SFLAG_INSYSMEM;
1303 HeapFree(GetProcessHeap(), 0, b_info);
1305 /* Use the dib section from now on */
1306 This->resource.allocatedMemory = This->dib.bitmap_data;
1308 /* Now allocate a HDC */
1309 This->hDC = CreateCompatibleDC(0);
1310 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1311 TRACE("using wined3d palette %p\n", This->palette);
1312 SelectPalette(This->hDC,
1313 This->palette ? This->palette->hpal : 0,
1314 FALSE);
1316 This->Flags |= SFLAG_DIBSECTION;
1319 /* Lock the surface */
1320 hr = IWineD3DSurface_LockRect(iface,
1321 &lock,
1322 NULL,
1324 if(FAILED(hr)) {
1325 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1326 /* keep the dib section */
1327 return hr;
1330 if(This->resource.format == WINED3DFMT_P8 ||
1331 This->resource.format == WINED3DFMT_A8P8) {
1332 unsigned int n;
1333 if(This->palette) {
1334 PALETTEENTRY ent[256];
1336 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1337 for (n=0; n<256; n++) {
1338 col[n].rgbRed = ent[n].peRed;
1339 col[n].rgbGreen = ent[n].peGreen;
1340 col[n].rgbBlue = ent[n].peBlue;
1341 col[n].rgbReserved = 0;
1343 } else {
1344 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1346 for (n=0; n<256; n++) {
1347 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1348 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1349 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1350 col[n].rgbReserved = 0;
1354 SetDIBColorTable(This->hDC, 0, 256, col);
1357 *pHDC = This->hDC;
1358 TRACE("returning %p\n",*pHDC);
1359 This->Flags |= SFLAG_DCINUSE;
1361 return WINED3D_OK;
1364 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1365 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1367 TRACE("(%p)->(%p)\n",This,hDC);
1369 if (!(This->Flags & SFLAG_DCINUSE))
1370 return WINED3DERR_INVALIDCALL;
1372 /* we locked first, so unlock now */
1373 IWineD3DSurface_UnlockRect(iface);
1375 This->Flags &= ~SFLAG_DCINUSE;
1377 return WINED3D_OK;
1380 /* ******************************************************
1381 IWineD3DSurface Internal (No mapping to directx api) parts follow
1382 ****************************************************** */
1384 static 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) {
1385 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1386 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1388 /* Default values: From the surface */
1389 *format = formatEntry->glFormat;
1390 *internal = formatEntry->glInternal;
1391 *type = formatEntry->glType;
1392 *convert = NO_CONVERSION;
1393 *target_bpp = This->bytesPerPixel;
1395 /* Ok, now look if we have to do any conversion */
1396 switch(This->resource.format) {
1397 case WINED3DFMT_P8:
1398 /* ****************
1399 Paletted Texture
1400 **************** */
1401 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1402 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1404 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1405 *format = GL_RGBA;
1406 *internal = GL_RGBA;
1407 *type = GL_UNSIGNED_BYTE;
1408 *target_bpp = 4;
1409 if(colorkey_active) {
1410 *convert = CONVERT_PALETTED_CK;
1411 } else {
1412 *convert = CONVERT_PALETTED;
1416 break;
1418 case WINED3DFMT_R3G3B2:
1419 /* **********************
1420 GL_UNSIGNED_BYTE_3_3_2
1421 ********************** */
1422 if (colorkey_active) {
1423 /* This texture format will never be used.. So do not care about color keying
1424 up until the point in time it will be needed :-) */
1425 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1427 break;
1429 case WINED3DFMT_R5G6B5:
1430 if (colorkey_active) {
1431 *convert = CONVERT_CK_565;
1432 *format = GL_RGBA;
1433 *internal = GL_RGBA;
1434 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1436 break;
1438 case WINED3DFMT_R8G8B8:
1439 if (colorkey_active) {
1440 *convert = CONVERT_CK_RGB24;
1441 *format = GL_RGBA;
1442 *internal = GL_RGBA;
1443 *type = GL_UNSIGNED_INT_8_8_8_8;
1444 *target_bpp = 4;
1446 break;
1448 case WINED3DFMT_X8R8G8B8:
1449 if (colorkey_active) {
1450 *convert = CONVERT_RGB32_888;
1451 *format = GL_RGBA;
1452 *internal = GL_RGBA;
1453 *type = GL_UNSIGNED_INT_8_8_8_8;
1455 break;
1457 case WINED3DFMT_V8U8:
1458 /* TODO: GL_ATI_envmap_bumpmap provides suitable formats.
1459 * use it instead of converting
1460 * Remember to adjust the texbem instruction in the shader
1462 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1463 *convert = CONVERT_V8U8;
1464 *format = GL_BGR;
1465 *internal = GL_RGB8;
1466 *type = GL_BYTE;
1467 *target_bpp = 3;
1468 break;
1470 case WINED3DFMT_X8L8V8U8:
1471 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1472 FIXME("Conversion for D3D_X8L8V8U8 not implemented\n");
1473 *format = GL_BGRA;
1474 *internal = GL_RGBA8;
1475 *type = GL_BYTE;
1476 *target_bpp = 4;
1477 break;
1479 case WINED3DFMT_Q8W8V8U8:
1480 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1481 FIXME("Conversion for D3D_Q8W8V8U8 not implemented\n");
1482 *format = GL_BGRA;
1483 *internal = GL_RGBA8;
1484 *type = GL_BYTE;
1485 *target_bpp = 4;
1486 break;
1488 case WINED3DFMT_V16U16:
1489 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1490 FIXME("Conversion for D3D_V16U16 not implemented\n");
1491 *format = GL_COLOR_INDEX;
1492 *internal = GL_COLOR_INDEX;
1493 *type = GL_SHORT;
1494 *target_bpp = 4;
1495 break;
1497 default:
1498 break;
1501 return WINED3D_OK;
1504 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1505 BYTE *source, *dest;
1506 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1508 switch (convert) {
1509 case NO_CONVERSION:
1511 memcpy(dst, src, pitch * height);
1512 break;
1514 case CONVERT_PALETTED:
1515 case CONVERT_PALETTED_CK:
1517 IWineD3DPaletteImpl* pal = surf->palette;
1518 BYTE table[256][4];
1519 unsigned int i;
1520 unsigned int x, y;
1522 if( pal == NULL) {
1523 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1526 if (pal == NULL) {
1527 /* Still no palette? Use the device's palette */
1528 /* Get the surface's palette */
1529 for (i = 0; i < 256; i++) {
1530 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1532 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1533 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1534 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1535 if ((convert == CONVERT_PALETTED_CK) &&
1536 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1537 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1538 /* We should maybe here put a more 'neutral' color than the standard bright purple
1539 one often used by application to prevent the nice purple borders when bi-linear
1540 filtering is on */
1541 table[i][3] = 0x00;
1542 } else {
1543 table[i][3] = 0xFF;
1546 } else {
1547 TRACE("Using surface palette %p\n", pal);
1548 /* Get the surface's palette */
1549 for (i = 0; i < 256; i++) {
1550 table[i][0] = pal->palents[i].peRed;
1551 table[i][1] = pal->palents[i].peGreen;
1552 table[i][2] = pal->palents[i].peBlue;
1553 if ((convert == CONVERT_PALETTED_CK) &&
1554 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1555 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1556 /* We should maybe here put a more 'neutral' color than the standard bright purple
1557 one often used by application to prevent the nice purple borders when bi-linear
1558 filtering is on */
1559 table[i][3] = 0x00;
1560 } else {
1561 table[i][3] = 0xFF;
1566 for (y = 0; y < height; y++)
1568 source = src + pitch * y;
1569 dest = dst + outpitch * y;
1570 /* This is an 1 bpp format, using the width here is fine */
1571 for (x = 0; x < width; x++) {
1572 BYTE color = *source++;
1573 *dest++ = table[color][0];
1574 *dest++ = table[color][1];
1575 *dest++ = table[color][2];
1576 *dest++ = table[color][3];
1580 break;
1582 case CONVERT_CK_565:
1584 /* Converting the 565 format in 5551 packed to emulate color-keying.
1586 Note : in all these conversion, it would be best to average the averaging
1587 pixels to get the color of the pixel that will be color-keyed to
1588 prevent 'color bleeding'. This will be done later on if ever it is
1589 too visible.
1591 Note2: Nvidia documents say that their driver does not support alpha + color keying
1592 on the same surface and disables color keying in such a case
1594 unsigned int x, y;
1595 WORD *Source;
1596 WORD *Dest;
1598 TRACE("Color keyed 565\n");
1600 for (y = 0; y < height; y++) {
1601 Source = (WORD *) (src + y * pitch);
1602 Dest = (WORD *) (dst + y * outpitch);
1603 for (x = 0; x < width; x++ ) {
1604 WORD color = *Source++;
1605 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1606 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1607 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1608 *Dest |= 0x0001;
1610 Dest++;
1614 break;
1616 case CONVERT_V8U8:
1618 unsigned int x, y;
1619 short *Source;
1620 unsigned char *Dest;
1621 for(y = 0; y < height; y++) {
1622 Source = (short *) (src + y * pitch);
1623 Dest = (unsigned char *) (dst + y * outpitch);
1624 for (x = 0; x < width; x++ ) {
1625 long color = (*Source++);
1626 /* B */ Dest[0] = 0xff;
1627 /* G */ Dest[1] = (color >> 8) + 128; /* V */
1628 /* R */ Dest[2] = (color) + 128; /* U */
1629 Dest += 3;
1632 break;
1635 default:
1636 ERR("Unsupported conversation type %d\n", convert);
1638 return WINED3D_OK;
1641 /* This function is used in case of 8bit paletted textures to upload the palette.
1642 For now it only supports GL_EXT_paletted_texture extension but support for other
1643 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1645 static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1646 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1647 IWineD3DPaletteImpl* pal = This->palette;
1648 BYTE table[256][4];
1649 int i;
1651 if (pal == NULL) {
1652 /* Still no palette? Use the device's palette */
1653 /* Get the surface's palette */
1654 for (i = 0; i < 256; i++) {
1655 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1657 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1658 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1659 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1660 if ((convert == CONVERT_PALETTED_CK) &&
1661 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1662 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1663 /* We should maybe here put a more 'neutral' color than the standard bright purple
1664 one often used by application to prevent the nice purple borders when bi-linear
1665 filtering is on */
1666 table[i][3] = 0x00;
1667 } else {
1668 table[i][3] = 0xFF;
1671 } else {
1672 TRACE("Using surface palette %p\n", pal);
1673 /* Get the surface's palette */
1674 for (i = 0; i < 256; i++) {
1675 table[i][0] = pal->palents[i].peRed;
1676 table[i][1] = pal->palents[i].peGreen;
1677 table[i][2] = pal->palents[i].peBlue;
1678 if ((convert == CONVERT_PALETTED_CK) &&
1679 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1680 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1681 /* We should maybe here put a more 'neutral' color than the standard bright purple
1682 one often used by application to prevent the nice purple borders when bi-linear
1683 filtering is on */
1684 table[i][3] = 0x00;
1685 } else {
1686 table[i][3] = 0xFF;
1690 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1693 static BOOL palette9_changed(IWineD3DSurfaceImpl *This) {
1694 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1696 if(This->palette || (This->resource.format != WINED3DFMT_P8 && This->resource.format != WINED3DFMT_A8P8)) {
1697 /* If a ddraw-style palette is attached assume no d3d9 palette change.
1698 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
1700 return FALSE;
1703 if(This->palette9) {
1704 if(memcmp(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256) == 0) {
1705 return FALSE;
1707 } else {
1708 This->palette9 = (PALETTEENTRY *) HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1710 memcpy(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
1711 return TRUE;
1714 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1715 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1716 GLenum format, internal, type;
1717 CONVERT_TYPES convert;
1718 int bpp;
1719 int width, pitch, outpitch;
1720 BYTE *mem;
1722 if (!(This->Flags & SFLAG_INTEXTURE)) {
1723 TRACE("Reloading because surface is dirty\n");
1724 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1725 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1726 /* Reload: vice versa OR */
1727 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1728 /* Also reload: Color key is active AND the color key has changed */
1729 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1730 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1731 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1732 TRACE("Reloading because of color keying\n");
1733 } else if(palette9_changed(This)) {
1734 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
1735 } else {
1736 TRACE("surface is already in texture\n");
1737 return WINED3D_OK;
1740 This->Flags |= SFLAG_INTEXTURE;
1742 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1743 * These resources are not bound by device size or format restrictions. Because of this,
1744 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1745 * However, these resources can always be created, locked, and copied.
1747 if (This->resource.pool == WINED3DPOOL_SCRATCH )
1749 FIXME("(%p) Operation not supported for scratch textures\n",This);
1750 return WINED3DERR_INVALIDCALL;
1753 if (This->Flags & SFLAG_INDRAWABLE) {
1754 if (This->glDescription.level != 0)
1755 FIXME("Surface in texture is only supported for level 0\n");
1756 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1757 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1758 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1759 This->resource.format == WINED3DFMT_DXT5)
1760 FIXME("Format %d not supported\n", This->resource.format);
1761 else {
1762 GLint prevRead;
1764 ENTER_GL();
1765 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1766 vcheckGLcall("glGetIntegerv");
1767 glReadBuffer(This->resource.wineD3DDevice->offscreenBuffer);
1768 vcheckGLcall("glReadBuffer");
1770 glCopyTexImage2D(This->glDescription.target,
1771 This->glDescription.level,
1772 This->glDescription.glFormatInternal,
1775 This->currentDesc.Width,
1776 This->currentDesc.Height,
1779 checkGLcall("glCopyTexImage2D");
1780 glReadBuffer(prevRead);
1781 vcheckGLcall("glReadBuffer");
1783 LEAVE_GL();
1785 TRACE("Updated target %d\n", This->glDescription.target);
1787 return WINED3D_OK;
1789 /* Otherwise: System memory copy must be most up to date */
1791 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1792 This->Flags |= SFLAG_GLCKEY;
1793 This->glCKey = This->SrcBltCKey;
1795 else This->Flags &= ~SFLAG_GLCKEY;
1797 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1799 /* The width is in 'length' not in bytes */
1800 width = This->currentDesc.Width;
1801 pitch = IWineD3DSurface_GetPitch(iface);
1803 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1804 int height = This->currentDesc.Height;
1806 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1807 outpitch = width * bpp;
1808 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1810 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1811 if(!mem) {
1812 ERR("Out of memory %d, %d!\n", outpitch, height);
1813 return WINED3DERR_OUTOFVIDEOMEMORY;
1815 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1817 This->Flags |= SFLAG_CONVERTED;
1818 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1819 d3dfmt_p8_upload_palette(iface, convert);
1820 This->Flags &= ~SFLAG_CONVERTED;
1821 mem = This->resource.allocatedMemory;
1822 } else {
1823 This->Flags &= ~SFLAG_CONVERTED;
1824 mem = This->resource.allocatedMemory;
1827 /* Make sure the correct pitch is used */
1828 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1830 if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1831 TRACE("non power of two support\n");
1832 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1833 if (mem) {
1834 surface_upload_data(This, This->currentDesc.Width, This->currentDesc.Height, format, type, mem);
1836 } else {
1837 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1838 if (mem) {
1839 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1843 /* Restore the default pitch */
1844 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1846 if (mem != This->resource.allocatedMemory)
1847 HeapFree(GetProcessHeap(), 0, mem);
1849 #if 0
1851 static unsigned int gen = 0;
1852 char buffer[4096];
1853 ++gen;
1854 if ((gen % 10) == 0) {
1855 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1856 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1859 * debugging crash code
1860 if (gen == 250) {
1861 void** test = NULL;
1862 *test = 0;
1866 #endif
1868 if (!(This->Flags & SFLAG_DONOTFREE)) {
1869 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1870 This->resource.allocatedMemory = NULL;
1871 This->Flags &= ~SFLAG_INSYSMEM;
1874 return WINED3D_OK;
1877 #include <errno.h>
1878 #include <stdio.h>
1879 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1880 FILE* f = NULL;
1881 UINT i, y;
1882 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1883 char *allocatedMemory;
1884 char *textureRow;
1885 IWineD3DSwapChain *swapChain = NULL;
1886 int width, height;
1887 GLuint tmpTexture = 0;
1888 DWORD color;
1889 /*FIXME:
1890 Textures my not be stored in ->allocatedgMemory and a GlTexture
1891 so we should lock the surface before saving a snapshot, or at least check that
1893 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1894 by calling GetTexImage and in compressed form by calling
1895 GetCompressedTexImageARB. Queried compressed images can be saved and
1896 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1897 texture images do not need to be processed by the GL and should
1898 significantly improve texture loading performance relative to uncompressed
1899 images. */
1901 /* Setup the width and height to be the internal texture width and height. */
1902 width = This->pow2Width;
1903 height = This->pow2Height;
1904 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1905 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1907 if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) {
1908 /* if were not a real texture then read the back buffer into a real texture */
1909 /* we don't want to interfere with the back buffer so read the data into a temporary
1910 * texture and then save the data out of the temporary texture
1912 GLint prevRead;
1913 ENTER_GL();
1914 TRACE("(%p) Reading render target into texture\n", This);
1915 glEnable(GL_TEXTURE_2D);
1917 glGenTextures(1, &tmpTexture);
1918 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1920 glTexImage2D(GL_TEXTURE_2D,
1922 GL_RGBA,
1923 width,
1924 height,
1925 0/*border*/,
1926 GL_RGBA,
1927 GL_UNSIGNED_INT_8_8_8_8_REV,
1928 NULL);
1930 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1931 vcheckGLcall("glGetIntegerv");
1932 glReadBuffer(swapChain ? GL_BACK : This->resource.wineD3DDevice->offscreenBuffer);
1933 vcheckGLcall("glReadBuffer");
1934 glCopyTexImage2D(GL_TEXTURE_2D,
1936 GL_RGBA,
1939 width,
1940 height,
1943 checkGLcall("glCopyTexImage2D");
1944 glReadBuffer(prevRead);
1945 LEAVE_GL();
1947 } else { /* bind the real texture, and make sure it up to date */
1948 IWineD3DSurface_PreLoad(iface);
1950 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1951 ENTER_GL();
1952 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1953 glGetTexImage(GL_TEXTURE_2D,
1954 This->glDescription.level,
1955 GL_RGBA,
1956 GL_UNSIGNED_INT_8_8_8_8_REV,
1957 allocatedMemory);
1958 checkGLcall("glTexImage2D");
1959 if (tmpTexture) {
1960 glBindTexture(GL_TEXTURE_2D, 0);
1961 glDeleteTextures(1, &tmpTexture);
1963 LEAVE_GL();
1965 f = fopen(filename, "w+");
1966 if (NULL == f) {
1967 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1968 return WINED3DERR_INVALIDCALL;
1970 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1971 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1972 /* TGA header */
1973 fputc(0,f);
1974 fputc(0,f);
1975 fputc(2,f);
1976 fputc(0,f);
1977 fputc(0,f);
1978 fputc(0,f);
1979 fputc(0,f);
1980 fputc(0,f);
1981 fputc(0,f);
1982 fputc(0,f);
1983 fputc(0,f);
1984 fputc(0,f);
1985 /* short width*/
1986 fwrite(&width,2,1,f);
1987 /* short height */
1988 fwrite(&height,2,1,f);
1989 /* format rgba */
1990 fputc(0x20,f);
1991 fputc(0x28,f);
1992 /* raw data */
1993 /* 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*/
1994 if(swapChain)
1995 textureRow = allocatedMemory + (width * (height - 1) *4);
1996 else
1997 textureRow = allocatedMemory;
1998 for (y = 0 ; y < height; y++) {
1999 for (i = 0; i < width; i++) {
2000 color = *((DWORD*)textureRow);
2001 fputc((color >> 16) & 0xFF, f); /* B */
2002 fputc((color >> 8) & 0xFF, f); /* G */
2003 fputc((color >> 0) & 0xFF, f); /* R */
2004 fputc((color >> 24) & 0xFF, f); /* A */
2005 textureRow += 4;
2007 /* take two rows of the pointer to the texture memory */
2008 if(swapChain)
2009 (textureRow-= width << 3);
2012 TRACE("Closing file\n");
2013 fclose(f);
2015 if(swapChain) {
2016 IWineD3DSwapChain_Release(swapChain);
2018 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2019 return WINED3D_OK;
2023 * Slightly inefficient way to handle multiple dirty rects but it works :)
2025 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2026 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2027 IWineD3DBaseTexture *baseTexture = NULL;
2028 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
2029 if (NULL != pDirtyRect) {
2030 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2031 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2032 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2033 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2034 } else {
2035 This->dirtyRect.left = 0;
2036 This->dirtyRect.top = 0;
2037 This->dirtyRect.right = This->currentDesc.Width;
2038 This->dirtyRect.bottom = This->currentDesc.Height;
2040 TRACE("(%p) : Dirty: yes, Rect:(%d,%d,%d,%d)\n", This, This->dirtyRect.left,
2041 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2042 /* if the container is a basetexture then mark it dirty. */
2043 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2044 TRACE("Passing to conatiner\n");
2045 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2046 IWineD3DBaseTexture_Release(baseTexture);
2048 return WINED3D_OK;
2051 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2052 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2054 TRACE("This %p, container %p\n", This, container);
2056 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2058 TRACE("Setting container to %p from %p\n", container, This->container);
2059 This->container = container;
2061 return WINED3D_OK;
2064 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2065 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2066 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2068 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2069 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2070 return WINED3DERR_INVALIDCALL;
2073 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2074 if (format == WINED3DFMT_UNKNOWN) {
2075 This->resource.size = 0;
2076 } else if (format == WINED3DFMT_DXT1) {
2077 /* DXT1 is half byte per pixel */
2078 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2080 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2081 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2082 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2083 } else {
2084 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2085 This->resource.size *= This->pow2Height;
2089 /* Setup some glformat defaults */
2090 This->glDescription.glFormat = formatEntry->glFormat;
2091 This->glDescription.glFormatInternal = formatEntry->glInternal;
2092 This->glDescription.glType = formatEntry->glType;
2094 if (format != WINED3DFMT_UNKNOWN) {
2095 This->bytesPerPixel = formatEntry->bpp;
2096 } else {
2097 This->bytesPerPixel = 0;
2100 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2102 This->resource.format = format;
2104 TRACE("(%p) : Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
2106 return WINED3D_OK;
2109 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2110 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2112 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2113 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2114 ERR("Not supported on render targets\n");
2115 return WINED3DERR_INVALIDCALL;
2118 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2119 WARN("Surface is locked or the HDC is in use\n");
2120 return WINED3DERR_INVALIDCALL;
2123 if(Mem && Mem != This->resource.allocatedMemory) {
2125 /* Do I have to copy the old surface content? */
2126 if(This->Flags & SFLAG_DIBSECTION) {
2127 /* Release the DC. No need to hold the critical section for the update
2128 * Thread because this thread runs only on front buffers, but this method
2129 * fails for render targets in the check above.
2131 SelectObject(This->hDC, This->dib.holdbitmap);
2132 DeleteDC(This->hDC);
2133 /* Release the DIB section */
2134 DeleteObject(This->dib.DIBsection);
2135 This->dib.bitmap_data = NULL;
2136 This->resource.allocatedMemory = NULL;
2137 This->hDC = NULL;
2138 This->Flags &= ~SFLAG_DIBSECTION;
2139 } else if(!(This->Flags & SFLAG_USERPTR)) {
2140 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2142 This->resource.allocatedMemory = Mem;
2143 This->Flags |= SFLAG_USERPTR;
2144 } else if(This->Flags & SFLAG_USERPTR) {
2145 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2146 This->resource.allocatedMemory = NULL;
2147 This->Flags &= ~SFLAG_USERPTR;
2149 return WINED3D_OK;
2152 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2153 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2154 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2155 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2157 /* Flipping is only supported on RenderTargets */
2158 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2160 if(override) {
2161 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2162 * FIXME("(%p) Target override is not supported by now\n", This);
2163 * Additionally, it isn't really possible to support triple-buffering
2164 * properly on opengl at all
2168 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2169 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2172 /* Does a direct frame buffer -> texture copy. Stretching is done
2173 * with single pixel copy calls
2175 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2176 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2177 float xrel, yrel;
2178 UINT row;
2179 BOOL warned = FALSE; /* deliberately not static */
2180 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2182 ENTER_GL();
2184 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2186 /* Bind the target texture */
2187 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2188 checkGLcall("glBindTexture");
2189 if(!swapchain) {
2190 glReadBuffer(myDevice->offscreenBuffer);
2191 } else if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2192 glReadBuffer(GL_BACK);
2193 } else {
2194 glReadBuffer(GL_FRONT);
2196 checkGLcall("glReadBuffer");
2198 xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
2199 yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
2201 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2202 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2205 if(upsidedown &&
2206 !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) &&
2207 !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2208 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2210 glCopyTexSubImage2D(This->glDescription.target,
2211 This->glDescription.level,
2212 drect->x1, drect->y1, /* xoffset, yoffset */
2213 srect->x1, Src->currentDesc.Height - srect->y2,
2214 drect->x2 - drect->x1, drect->y2 - drect->y1);
2215 } else {
2216 UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
2217 /* I have to process this row by row to swap the image,
2218 * otherwise it would be upside down, so streching in y direction
2219 * doesn't cost extra time
2221 * However, streching in x direction can be avoided if not necessary
2223 for(row = drect->y1; row < drect->y2; row++) {
2224 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2225 /* Well, that stuff works, but it's very slow.
2226 * find a better way instead
2228 UINT col;
2230 if(!warned) {
2231 warned = TRUE;
2232 FIXME("Doing a pixel by pixel render target -> texture copy, expect performance issues\n");
2235 for(col = drect->x1; col < drect->x2; col++) {
2236 glCopyTexSubImage2D(This->glDescription.target,
2237 This->glDescription.level,
2238 drect->x1 + col, row, /* xoffset, yoffset */
2239 srect->x1 + col * xrel, yoffset - (int) (row * yrel),
2240 1, 1);
2242 } else {
2243 glCopyTexSubImage2D(This->glDescription.target,
2244 This->glDescription.level,
2245 drect->x1, row, /* xoffset, yoffset */
2246 srect->x1, yoffset - (int) (row * yrel),
2247 drect->x2-drect->x1, 1);
2252 vcheckGLcall("glCopyTexSubImage2D");
2253 LEAVE_GL();
2256 /* Uses the hardware to stretch and flip the image */
2257 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2258 GLuint src, backup = 0;
2259 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2260 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2261 float left, right, top, bottom; /* Texture coordinates */
2262 UINT fbwidth = Src->currentDesc.Width;
2263 UINT fbheight = Src->currentDesc.Height;
2264 GLenum drawBuffer = GL_BACK;
2266 TRACE("Using hwstretch blit\n");
2267 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2268 ENTER_GL();
2269 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2271 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2272 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2274 if(GL_LIMITS(aux_buffers) >= 2) {
2275 /* Got more than one aux buffer? Use the 2nd aux buffer */
2276 drawBuffer = GL_AUX1;
2277 } else if((swapchain || myDevice->offscreenBuffer == GL_BACK) && GL_LIMITS(aux_buffers) >= 1) {
2278 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2279 drawBuffer = GL_AUX0;
2282 if(!swapchain && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2283 glGenTextures(1, &backup);
2284 checkGLcall("glGenTextures\n");
2285 glBindTexture(GL_TEXTURE_2D, backup);
2286 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2287 } else {
2288 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2289 * we are reading from the back buffer, the backup can be used as source texture
2291 if(Src->glDescription.textureName == 0) {
2292 /* Get it a description */
2293 IWineD3DSurface_PreLoad(SrcSurface);
2295 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2296 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2298 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2299 Src->Flags &= ~SFLAG_INTEXTURE;
2302 glReadBuffer(GL_BACK);
2303 checkGLcall("glReadBuffer(GL_BACK)");
2305 /* TODO: Only back up the part that will be overwritten */
2306 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2307 0, 0 /* read offsets */,
2308 0, 0,
2309 fbwidth,
2310 fbheight);
2312 checkGLcall("glCopyTexSubImage2D");
2314 /* No issue with overriding these - the sampler is dirty due to blit usage */
2315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2316 checkGLcall("glTexParameteri");
2317 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2318 checkGLcall("glTexParameteri");
2320 if(!swapchain || (IWineD3DSurface *) Src == swapchain->backBuffer[0]) {
2321 src = backup ? backup : Src->glDescription.textureName;
2322 } else {
2323 glReadBuffer(GL_FRONT);
2324 checkGLcall("glReadBuffer(GL_FRONT)");
2326 glGenTextures(1, &src);
2327 checkGLcall("glGenTextures(1, &src)");
2328 glBindTexture(GL_TEXTURE_2D, src);
2329 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2331 /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2332 * out for power of 2 sizes
2334 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2335 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2336 checkGLcall("glTexImage2D");
2337 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2338 0, 0 /* read offsets */,
2339 0, 0,
2340 fbwidth,
2341 fbheight);
2343 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2344 checkGLcall("glTexParameteri");
2345 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2346 checkGLcall("glTexParameteri");
2348 glReadBuffer(GL_BACK);
2349 checkGLcall("glReadBuffer(GL_BACK)");
2351 checkGLcall("glEnd and previous");
2353 left = (float) srect->x1 / (float) Src->pow2Width;
2354 right = (float) srect->x2 / (float) Src->pow2Width;
2356 if(upsidedown) {
2357 top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2358 bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2359 } else {
2360 top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2361 bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2364 /* draw the source texture stretched and upside down. The correct surface is bound already */
2365 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2368 glDrawBuffer(drawBuffer);
2369 glReadBuffer(drawBuffer);
2371 glBegin(GL_QUADS);
2372 /* bottom left */
2373 glTexCoord2f(left, bottom);
2374 glVertex2i(0, fbheight);
2376 /* top left */
2377 glTexCoord2f(left, top);
2378 glVertex2i(0, fbheight - drect->y2 - drect->y1);
2380 /* top right */
2381 glTexCoord2f(right, top);
2382 glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
2384 /* bottom right */
2385 glTexCoord2f(right, bottom);
2386 glVertex2i(drect->x2 - drect->x1, fbheight);
2387 glEnd();
2388 checkGLcall("glEnd and previous");
2390 /* Now read the stretched and upside down image into the destination texture */
2391 glBindTexture(This->glDescription.target, This->glDescription.textureName);
2392 checkGLcall("glBindTexture");
2393 glCopyTexSubImage2D(This->glDescription.target,
2395 drect->x1, drect->y1, /* xoffset, yoffset */
2396 0, 0, /* We blitted the image to the origin */
2397 drect->x2 - drect->x1, drect->y2 - drect->y1);
2398 checkGLcall("glCopyTexSubImage2D");
2400 /* Write the back buffer backup back */
2401 glBindTexture(GL_TEXTURE_2D, backup ? backup : Src->glDescription.textureName);
2402 checkGLcall("glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName)");
2404 if(drawBuffer == GL_BACK) {
2405 glBegin(GL_QUADS);
2406 /* top left */
2407 glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height);
2408 glVertex2i(0, 0);
2410 /* bottom left */
2411 glTexCoord2f(0.0, 0.0);
2412 glVertex2i(0, fbheight);
2414 /* bottom right */
2415 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0);
2416 glVertex2i(fbwidth, Src->currentDesc.Height);
2418 /* top right */
2419 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
2420 glVertex2i(fbwidth, 0);
2421 glEnd();
2422 } else {
2423 /* Restore the old draw buffer */
2424 glDrawBuffer(GL_BACK);
2427 /* Cleanup */
2428 if(src != Src->glDescription.textureName && src != backup) {
2429 glDeleteTextures(1, &src);
2430 checkGLcall("glDeleteTextures(1, &src)");
2432 if(backup) {
2433 glDeleteTextures(1, &backup);
2434 checkGLcall("glDeleteTextures(1, &backup)");
2436 LEAVE_GL();
2439 /* Not called from the VTable */
2440 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2441 WINED3DRECT rect;
2442 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2443 IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
2444 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2445 BOOL SrcOK = TRUE;
2447 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2449 /* Get the swapchain. One of the surfaces has to be a primary surface */
2450 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
2451 if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
2452 if(Src) {
2453 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
2454 if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
2457 /* Early sort out of cases where no render target is used */
2458 if(!dstSwapchain && !srcSwapchain &&
2459 SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2460 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
2461 return WINED3DERR_INVALIDCALL;
2464 /* No destination color keying supported */
2465 if(Flags & (DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE)) {
2466 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2467 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2468 return WINED3DERR_INVALIDCALL;
2471 if (DestRect) {
2472 rect.x1 = DestRect->left;
2473 rect.y1 = DestRect->top;
2474 rect.x2 = DestRect->right;
2475 rect.y2 = DestRect->bottom;
2476 } else {
2477 rect.x1 = 0;
2478 rect.y1 = 0;
2479 rect.x2 = This->currentDesc.Width;
2480 rect.y2 = This->currentDesc.Height;
2483 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
2484 if(dstSwapchain && dstSwapchain == srcSwapchain) {
2485 /* Half-life does a Blt from the back buffer to the front buffer,
2486 * Full surface size, no flags... Use present instead
2489 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2490 if( SrcRect ) {
2491 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2492 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2493 SrcOK = TRUE;
2495 } else {
2496 SrcOK = TRUE;
2499 /* Check the Destination rect and the surface sizes */
2500 if(SrcOK &&
2501 (rect.x1 == 0) && (rect.y1 == 0) &&
2502 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2503 (This->currentDesc.Width == Src->currentDesc.Width) &&
2504 (This->currentDesc.Height == Src->currentDesc.Height)) {
2505 /* These flags are unimportant for the flag check, remove them */
2507 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2508 if( dstSwapchain->backBuffer && ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) &&
2509 SrcSurface == dstSwapchain->backBuffer[0] ) {
2511 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
2513 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2514 * take very long, while a flip is fast.
2515 * This applies to Half-Life, which does such Blts every time it finished
2516 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2517 * menu. This is also used by all apps when they do windowed rendering
2519 * The problem is that flipping is not really the same as copying. After a
2520 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2521 * untouched. Therefore it's necessary to override the swap effect
2522 * and to set it back after the flip.
2525 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2527 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2528 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2529 NULL, NULL, 0, NULL);
2531 dstSwapchain->presentParms.SwapEffect = orig_swap;
2533 return WINED3D_OK;
2538 TRACE("Unsupported blit between buffers on the same swapchain\n");
2539 return WINED3DERR_INVALIDCALL;
2540 } else if((dstSwapchain || This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) &&
2541 (srcSwapchain || SrcSurface == myDevice->render_targets[0]) ) {
2542 ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n");
2543 return WINED3DERR_INVALIDCALL;
2546 if(srcSwapchain || SrcSurface == myDevice->render_targets[0]) {
2547 /* Blit from render target to texture */
2548 WINED3DRECT srect;
2549 BOOL upsideDown, stretchx;
2551 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2552 TRACE("Color keying not supported by frame buffer to texture blit\n");
2553 return WINED3DERR_INVALIDCALL;
2554 /* Destination color key is checked above */
2557 /* Call preload for the surface to make sure it isn't dirty */
2558 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2560 /* Make sure that the top pixel is always above the bottom pixel, and keep a seperate upside down flag
2561 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2563 if(SrcRect) {
2564 if(SrcRect->top < SrcRect->bottom) {
2565 srect.y1 = SrcRect->top;
2566 srect.y2 = SrcRect->bottom;
2567 upsideDown = FALSE;
2568 } else {
2569 srect.y1 = SrcRect->bottom;
2570 srect.y2 = SrcRect->top;
2571 upsideDown = TRUE;
2573 srect.x1 = SrcRect->left;
2574 srect.x2 = SrcRect->right;
2575 } else {
2576 srect.x1 = 0;
2577 srect.y1 = 0;
2578 srect.x2 = Src->currentDesc.Width;
2579 srect.y2 = Src->currentDesc.Height;
2580 upsideDown = FALSE;
2582 if(rect.x1 > rect.x2) {
2583 UINT tmp = rect.x2;
2584 rect.x2 = rect.x1;
2585 rect.x1 = tmp;
2586 upsideDown = !upsideDown;
2588 if(!srcSwapchain) {
2589 TRACE("Reading from an offscreen target\n");
2590 upsideDown = !upsideDown;
2593 if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
2594 stretchx = TRUE;
2595 } else {
2596 stretchx = FALSE;
2599 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2600 * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
2601 * not implemented by now). Otherwise:
2603 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2604 * -> If the app wants a image width an unscaled width, copy it line per line
2605 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
2606 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2607 * back buffer. This is slower than reading line per line, thus not used for flipping
2608 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2609 * pixel by pixel
2611 if(FALSE /* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) {
2612 TRACE("Using GL_EXT_framebuffer_blit for copying\n");
2613 } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
2614 rect.y2 - rect.y1 > Src->currentDesc.Height) {
2615 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
2616 fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2617 } else {
2618 TRACE("Using hardware stretching to flip / stretch the texture\n");
2619 fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2622 if(!(This->Flags & SFLAG_DONOTFREE)) {
2623 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2624 This->resource.allocatedMemory = NULL;
2625 } else {
2626 This->Flags &= ~SFLAG_INSYSMEM;
2628 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
2629 * path is never entered
2631 This->Flags |= SFLAG_INTEXTURE;
2633 return WINED3D_OK;
2634 } else if(Src) {
2635 /* Blit from offscreen surface to render target */
2636 float glTexCoord[4];
2637 DWORD oldCKeyFlags = Src->CKeyFlags;
2638 DDCOLORKEY oldBltCKey = This->SrcBltCKey;
2639 RECT SourceRectangle;
2640 GLint oldDraw;
2642 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2644 if(SrcRect) {
2645 SourceRectangle.left = SrcRect->left;
2646 SourceRectangle.right = SrcRect->right;
2647 SourceRectangle.top = SrcRect->top;
2648 SourceRectangle.bottom = SrcRect->bottom;
2649 } else {
2650 SourceRectangle.left = 0;
2651 SourceRectangle.right = Src->currentDesc.Width;
2652 SourceRectangle.top = 0;
2653 SourceRectangle.bottom = Src->currentDesc.Height;
2656 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2657 /* Fall back to software */
2658 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2659 SourceRectangle.left, SourceRectangle.top,
2660 SourceRectangle.right, SourceRectangle.bottom);
2661 return WINED3DERR_INVALIDCALL;
2664 /* Color keying: Check if we have to do a color keyed blt,
2665 * and if not check if a color key is activated.
2667 * Just modify the color keying parameters in the surface and restore them afterwards
2668 * The surface keeps track of the color key last used to load the opengl surface.
2669 * PreLoad will catch the change to the flags and color key and reload if neccessary.
2671 if(Flags & DDBLT_KEYSRC) {
2672 /* Use color key from surface */
2673 } else if(Flags & DDBLT_KEYSRCOVERRIDE) {
2674 /* Use color key from DDBltFx */
2675 Src->CKeyFlags |= DDSD_CKSRCBLT;
2676 This->SrcBltCKey = DDBltFx->ddckSrcColorkey;
2677 } else {
2678 /* Do not use color key */
2679 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2682 /* Now load the surface */
2683 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2685 ENTER_GL();
2687 /* Activate the destination context, set it up for blitting */
2688 ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
2690 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2691 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer) {
2692 TRACE("Drawing to front buffer\n");
2693 glDrawBuffer(GL_FRONT);
2694 checkGLcall("glDrawBuffer GL_FRONT");
2697 /* Bind the texture */
2698 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2699 checkGLcall("glBindTexture");
2701 /* No filtering for blts */
2702 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2703 GL_NEAREST);
2704 checkGLcall("glTexParameteri");
2705 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2706 GL_NEAREST);
2707 checkGLcall("glTexParameteri");
2708 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2709 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2710 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2711 checkGLcall("glTexEnvi");
2713 /* This is for color keying */
2714 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2715 glEnable(GL_ALPHA_TEST);
2716 checkGLcall("glEnable GL_ALPHA_TEST");
2717 glAlphaFunc(GL_NOTEQUAL, 0.0);
2718 checkGLcall("glAlphaFunc\n");
2719 } else {
2720 glDisable(GL_ALPHA_TEST);
2721 checkGLcall("glDisable GL_ALPHA_TEST");
2724 /* Draw a textured quad
2726 glBegin(GL_QUADS);
2728 glColor3d(1.0f, 1.0f, 1.0f);
2729 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2730 glVertex3f(rect.x1,
2731 rect.y1,
2732 0.0);
2734 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2735 glVertex3f(rect.x1, rect.y2, 0.0);
2737 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2738 glVertex3f(rect.x2,
2739 rect.y2,
2740 0.0);
2742 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2743 glVertex3f(rect.x2,
2744 rect.y1,
2745 0.0);
2746 glEnd();
2747 checkGLcall("glEnd");
2749 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2750 glDisable(GL_ALPHA_TEST);
2751 checkGLcall("glDisable(GL_ALPHA_TEST)");
2754 /* Unbind the texture */
2755 glBindTexture(GL_TEXTURE_2D, 0);
2756 checkGLcall("glEnable glBindTexture");
2758 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && oldDraw == GL_BACK) {
2759 glDrawBuffer(oldDraw);
2761 /* Restore the color key parameters */
2762 Src->CKeyFlags = oldCKeyFlags;
2763 This->SrcBltCKey = oldBltCKey;
2765 LEAVE_GL();
2767 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2768 This->Flags &= ~SFLAG_INSYSMEM;
2769 /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
2770 * is outdated now
2772 if(dstSwapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO) {
2773 This->Flags |= SFLAG_INDRAWABLE;
2774 This->Flags &= ~SFLAG_INTEXTURE;
2775 } else {
2776 This->Flags |= SFLAG_INTEXTURE;
2779 return WINED3D_OK;
2780 } else {
2781 /* Source-Less Blit to render target */
2782 if (Flags & DDBLT_COLORFILL) {
2783 /* This is easy to handle for the D3D Device... */
2784 DWORD color;
2786 TRACE("Colorfill\n");
2788 /* The color as given in the Blt function is in the format of the frame-buffer...
2789 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2791 if (This->resource.format == WINED3DFMT_P8) {
2792 if (This->palette) {
2793 color = ((0xFF000000) |
2794 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2795 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2796 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2797 } else {
2798 color = 0xFF000000;
2801 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2802 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2803 color = 0xFFFFFFFF;
2804 } else {
2805 color = ((0xFF000000) |
2806 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2807 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2808 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2811 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2812 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2813 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2815 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2816 color = DDBltFx->u5.dwFillColor;
2818 else {
2819 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2820 return WINED3DERR_INVALIDCALL;
2823 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2824 if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) {
2825 glDrawBuffer(GL_BACK);
2826 checkGLcall("glDrawBuffer(GL_BACK)");
2827 } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) {
2828 glDrawBuffer(GL_FRONT);
2829 checkGLcall("glDrawBuffer(GL_FRONT)");
2830 } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2831 glDrawBuffer(myDevice->offscreenBuffer);
2832 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer3)");
2833 } else {
2834 TRACE("Surface is higher back buffer, falling back to software\n");
2835 return WINED3DERR_INVALIDCALL;
2838 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2840 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2841 1 /* Number of rectangles */,
2842 &rect,
2843 WINED3DCLEAR_TARGET,
2844 color,
2845 0.0 /* Z */,
2846 0 /* Stencil */);
2848 /* Restore the original draw buffer */
2849 if(!dstSwapchain) {
2850 glDrawBuffer(myDevice->offscreenBuffer);
2851 } else if(dstSwapchain->backBuffer && dstSwapchain->backBuffer[0]) {
2852 glDrawBuffer(GL_BACK);
2854 vcheckGLcall("glDrawBuffer");
2856 return WINED3D_OK;
2860 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2861 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2862 return WINED3DERR_INVALIDCALL;
2865 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2866 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2867 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2868 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2869 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2870 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2872 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair */
2873 if(myDevice->inScene &&
2874 (iface == myDevice->stencilBufferTarget ||
2875 (SrcSurface && SrcSurface == myDevice->stencilBufferTarget))) {
2876 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2877 return WINED3DERR_INVALIDCALL;
2880 /* Special cases for RenderTargets */
2881 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2882 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2883 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2886 /* For the rest call the X11 surface implementation.
2887 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2888 * other Blts are rather rare
2890 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2893 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2894 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2895 TRACE("(%p)->(%x)\n", This, Flags);
2897 switch (Flags)
2899 case DDGBS_CANBLT:
2900 case DDGBS_ISBLTDONE:
2901 return DD_OK;
2903 default:
2904 return DDERR_INVALIDPARAMS;
2908 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2909 /* XXX: DDERR_INVALIDSURFACETYPE */
2911 TRACE("(%p)->(%08x)\n",iface,Flags);
2912 switch (Flags) {
2913 case DDGFS_CANFLIP:
2914 case DDGFS_ISFLIPDONE:
2915 return DD_OK;
2917 default:
2918 return DDERR_INVALIDPARAMS;
2922 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2923 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2924 TRACE("(%p)\n", This);
2926 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2929 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2930 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2931 TRACE("(%p)\n", This);
2933 /* So far we don't lose anything :) */
2934 This->Flags &= ~SFLAG_LOST;
2935 return WINED3D_OK;
2938 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2939 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2940 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2941 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2942 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2944 if(myDevice->inScene &&
2945 (iface == myDevice->stencilBufferTarget ||
2946 (Source && Source == myDevice->stencilBufferTarget))) {
2947 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2948 return WINED3DERR_INVALIDCALL;
2951 /* Special cases for RenderTargets */
2952 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2953 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2955 RECT SrcRect, DstRect;
2956 DWORD Flags=0;
2958 if(rsrc) {
2959 SrcRect.left = rsrc->left;
2960 SrcRect.top= rsrc->top;
2961 SrcRect.bottom = rsrc->bottom;
2962 SrcRect.right = rsrc->right;
2963 } else {
2964 SrcRect.left = 0;
2965 SrcRect.top = 0;
2966 SrcRect.right = srcImpl->currentDesc.Width;
2967 SrcRect.bottom = srcImpl->currentDesc.Height;
2970 DstRect.left = dstx;
2971 DstRect.top=dsty;
2972 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2973 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2975 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2976 if(trans & DDBLTFAST_SRCCOLORKEY)
2977 Flags |= DDBLT_KEYSRC;
2978 if(trans & DDBLTFAST_DESTCOLORKEY)
2979 Flags |= DDBLT_KEYDEST;
2980 if(trans & DDBLTFAST_WAIT)
2981 Flags |= DDBLT_WAIT;
2982 if(trans & DDBLTFAST_DONOTWAIT)
2983 Flags |= DDBLT_DONOTWAIT;
2985 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2989 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2992 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2993 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2994 TRACE("(%p)->(%p)\n", This, Pal);
2996 *Pal = (IWineD3DPalette *) This->palette;
2997 return DD_OK;
3000 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
3001 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3002 RGBQUAD col[256];
3003 IWineD3DPaletteImpl *pal = This->palette;
3004 unsigned int n;
3005 TRACE("(%p)\n", This);
3007 if(This->resource.format == WINED3DFMT_P8 ||
3008 This->resource.format == WINED3DFMT_A8P8)
3010 if(!This->Flags & SFLAG_INSYSMEM) {
3011 FIXME("Palette changed with surface that does not have an up to date system memory copy\n");
3013 TRACE("Dirtifying surface\n");
3014 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
3017 if(This->Flags & SFLAG_DIBSECTION) {
3018 TRACE("(%p): Updating the hdc's palette\n", This);
3019 for (n=0; n<256; n++) {
3020 if(pal) {
3021 col[n].rgbRed = pal->palents[n].peRed;
3022 col[n].rgbGreen = pal->palents[n].peGreen;
3023 col[n].rgbBlue = pal->palents[n].peBlue;
3024 } else {
3025 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3026 /* Use the default device palette */
3027 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
3028 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
3029 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
3031 col[n].rgbReserved = 0;
3033 SetDIBColorTable(This->hDC, 0, 256, col);
3036 return WINED3D_OK;
3039 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
3040 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3041 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
3042 TRACE("(%p)->(%p)\n", This, Pal);
3044 if(This->palette != NULL)
3045 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3046 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
3048 if(PalImpl != NULL) {
3049 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3050 /* Set the device's main palette if the palette
3051 * wasn't a primary palette before
3053 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
3054 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3055 unsigned int i;
3057 for(i=0; i < 256; i++) {
3058 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
3062 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
3065 This->palette = PalImpl;
3067 return IWineD3DSurface_RealizePalette(iface);
3070 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
3071 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3072 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
3074 if ((Flags & DDCKEY_COLORSPACE) != 0) {
3075 FIXME(" colorkey value not supported (%08x) !\n", Flags);
3076 return DDERR_INVALIDPARAMS;
3079 /* Dirtify the surface, but only if a key was changed */
3080 if(CKey) {
3081 switch (Flags & ~DDCKEY_COLORSPACE) {
3082 case DDCKEY_DESTBLT:
3083 This->DestBltCKey = *CKey;
3084 This->CKeyFlags |= DDSD_CKDESTBLT;
3085 break;
3087 case DDCKEY_DESTOVERLAY:
3088 This->DestOverlayCKey = *CKey;
3089 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
3090 break;
3092 case DDCKEY_SRCOVERLAY:
3093 This->SrcOverlayCKey = *CKey;
3094 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
3095 break;
3097 case DDCKEY_SRCBLT:
3098 This->SrcBltCKey = *CKey;
3099 This->CKeyFlags |= DDSD_CKSRCBLT;
3100 break;
3103 else {
3104 switch (Flags & ~DDCKEY_COLORSPACE) {
3105 case DDCKEY_DESTBLT:
3106 This->CKeyFlags &= ~DDSD_CKDESTBLT;
3107 break;
3109 case DDCKEY_DESTOVERLAY:
3110 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
3111 break;
3113 case DDCKEY_SRCOVERLAY:
3114 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
3115 break;
3117 case DDCKEY_SRCBLT:
3118 This->CKeyFlags &= ~DDSD_CKSRCBLT;
3119 break;
3123 return WINED3D_OK;
3126 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3127 /** Check against the maximum texture sizes supported by the video card **/
3128 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3130 TRACE("%p\n", This);
3131 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3132 /* one of three options
3133 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)
3134 2: Set the texture to the maxium size (bad idea)
3135 3: WARN and return WINED3DERR_NOTAVAILABLE;
3136 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.
3138 WARN("(%p) Creating an oversized surface\n", This);
3139 This->Flags |= SFLAG_OVERSIZE;
3141 /* This will be initialized on the first blt */
3142 This->glRect.left = 0;
3143 This->glRect.top = 0;
3144 This->glRect.right = 0;
3145 This->glRect.bottom = 0;
3146 } else {
3147 /* No oversize, gl rect is the full texture size */
3148 This->Flags &= ~SFLAG_OVERSIZE;
3149 This->glRect.left = 0;
3150 This->glRect.top = 0;
3151 This->glRect.right = This->pow2Width;
3152 This->glRect.bottom = This->pow2Height;
3155 return WINED3D_OK;
3158 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3159 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3160 DWORD ret;
3161 TRACE("(%p)\n", This);
3163 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3164 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3165 ie pitch = (width/4) * bytes per block */
3166 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3167 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3168 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3169 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3170 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3171 else {
3172 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3173 /* Surfaces are 32 bit aligned */
3174 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3176 TRACE("(%p) Returning %d\n", This, ret);
3177 return ret;
3180 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3181 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3183 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3185 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3187 TRACE("(%p): Not an overlay surface\n", This);
3188 return DDERR_NOTAOVERLAYSURFACE;
3191 return WINED3D_OK;
3194 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3195 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3197 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3199 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3201 TRACE("(%p): Not an overlay surface\n", This);
3202 return DDERR_NOTAOVERLAYSURFACE;
3205 return WINED3D_OK;
3208 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3209 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3210 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3212 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3214 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3216 TRACE("(%p): Not an overlay surface\n", This);
3217 return DDERR_NOTAOVERLAYSURFACE;
3220 return WINED3D_OK;
3223 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3224 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3225 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3226 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3228 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3230 TRACE("(%p): Not an overlay surface\n", This);
3231 return DDERR_NOTAOVERLAYSURFACE;
3234 return WINED3D_OK;
3237 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3239 /* IUnknown */
3240 IWineD3DSurfaceImpl_QueryInterface,
3241 IWineD3DSurfaceImpl_AddRef,
3242 IWineD3DSurfaceImpl_Release,
3243 /* IWineD3DResource */
3244 IWineD3DSurfaceImpl_GetParent,
3245 IWineD3DSurfaceImpl_GetDevice,
3246 IWineD3DSurfaceImpl_SetPrivateData,
3247 IWineD3DSurfaceImpl_GetPrivateData,
3248 IWineD3DSurfaceImpl_FreePrivateData,
3249 IWineD3DSurfaceImpl_SetPriority,
3250 IWineD3DSurfaceImpl_GetPriority,
3251 IWineD3DSurfaceImpl_PreLoad,
3252 IWineD3DSurfaceImpl_GetType,
3253 /* IWineD3DSurface */
3254 IWineD3DSurfaceImpl_GetContainer,
3255 IWineD3DSurfaceImpl_GetDesc,
3256 IWineD3DSurfaceImpl_LockRect,
3257 IWineD3DSurfaceImpl_UnlockRect,
3258 IWineD3DSurfaceImpl_GetDC,
3259 IWineD3DSurfaceImpl_ReleaseDC,
3260 IWineD3DSurfaceImpl_Flip,
3261 IWineD3DSurfaceImpl_Blt,
3262 IWineD3DSurfaceImpl_GetBltStatus,
3263 IWineD3DSurfaceImpl_GetFlipStatus,
3264 IWineD3DSurfaceImpl_IsLost,
3265 IWineD3DSurfaceImpl_Restore,
3266 IWineD3DSurfaceImpl_BltFast,
3267 IWineD3DSurfaceImpl_GetPalette,
3268 IWineD3DSurfaceImpl_SetPalette,
3269 IWineD3DSurfaceImpl_RealizePalette,
3270 IWineD3DSurfaceImpl_SetColorKey,
3271 IWineD3DSurfaceImpl_GetPitch,
3272 IWineD3DSurfaceImpl_SetMem,
3273 IWineD3DSurfaceImpl_SetOverlayPosition,
3274 IWineD3DSurfaceImpl_GetOverlayPosition,
3275 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3276 IWineD3DSurfaceImpl_UpdateOverlay,
3277 /* Internal use: */
3278 IWineD3DSurfaceImpl_AddDirtyRect,
3279 IWineD3DSurfaceImpl_LoadTexture,
3280 IWineD3DSurfaceImpl_SaveSnapshot,
3281 IWineD3DSurfaceImpl_SetContainer,
3282 IWineD3DSurfaceImpl_SetGlTextureDesc,
3283 IWineD3DSurfaceImpl_GetGlDesc,
3284 IWineD3DSurfaceImpl_GetData,
3285 IWineD3DSurfaceImpl_SetFormat,
3286 IWineD3DSurfaceImpl_PrivateSetup