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
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
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);
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);
65 GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory));
66 checkGLcall("glGetCompressedTexImageARB()");
75 if(This->Flags & SFLAG_CONVERTED) {
76 FIXME("Read back converted textures unsupported\n");
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);
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);
94 glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
95 This->glDescription.glType, mem);
96 checkGLcall("glGetTexImage()");
100 if (This->Flags & SFLAG_NONPOW2) {
101 LPBYTE src_data, dst_data;
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
119 * -----------------------------------
122 * we're repacking the data to the expected texture width
124 * |<-texture width ->| -->pow2width| /\
125 * |111111111111111111222222222222222| |
126 * |222333333333333333333444444444444| texture height
130 * | empty | pow2height
132 * -----------------------------------
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.
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");
175 TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data);
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");
187 TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This, width, height, data);
189 glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data);
190 checkGLcall("glTexSubImage2D");
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");
209 glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, NULL);
210 checkGLcall("glTexImage2D");
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);
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);
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);
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
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);
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;
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.. */
284 TRACE("Deleting texture %d\n", This->glDescription.textureName);
285 glDeleteTextures(1, &This->glDescription.textureName);
289 if(This->Flags & SFLAG_DIBSECTION) {
291 SelectObject(This->hDC, This->dib.holdbitmap);
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);
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);
354 TRACE("(%p) : About to load surface\n", This);
356 #if 0 /* TODO: context manager support */
357 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
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) */
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) */);
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);
411 ERR("Called without a valid ppContainer.\n");
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;
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;
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_DIRTY;
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) {
476 BYTE *row, *top, *bottom;
480 switch(This->resource.format)
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.
494 type = GL_UNSIGNED_BYTE;
496 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
498 ERR("Out of memory\n");
501 bpp = This->bytesPerPixel * 3;
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,
516 vcheckGLcall("glReadPixels");
518 /* TODO: Merge this with the palettization loop below for P8 targets */
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);
529 ERR("Out of memory\n");
530 if(This->resource.format == WINED3DFMT_P8) HeapFree(GetProcessHeap(), 0, mem);
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);
543 HeapFree(GetProcessHeap(), 0, row);
546 if(This->resource.format == WINED3DFMT_P8) {
548 DWORD width = pitch / 3;
551 pal = This->palette->palents;
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;
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
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_GLDIRTY; /* This is the marker that surface data has to be downloaded */
604 /* Calculate the correct start address to report */
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);
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) ||
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));
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
645 if(!(This->Flags & SFLAG_DYNLOCK)) {
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_GLDIRTY) ) {
655 TRACE("WINED3DLOCK_DISCARD flag passed, or local copy is up to date, not downloading data\n");
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;
670 ERR("The application tries to lock the render target, but render target locking is disabled\n");
673 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
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.
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.
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(GL_BACK);
695 srcIsUpsideDown = TRUE;
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);
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) {
718 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
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");
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_GLDIRTY;
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
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,
748 * GL_DEPTH_COMPONENT,
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 missing SFLAG_GLDIRTY 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");
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)) {
771 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
772 checkGLcall("glActiveTextureARB");
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_GLDIRTY;
786 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
789 IWineD3DBaseTexture *pBaseTexture;
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);
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, This->Flags & SFLAG_DIRTY ? 0 : 1);
810 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
812 GLint prev_rasterpos[4];
814 BOOL storechanged = FALSE, memory_allocated = FALSE;
818 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
820 glDisable(GL_TEXTURE_2D);
821 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
824 vcheckGLcall("glFlush");
825 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
826 vcheckGLcall("glIntegerv");
827 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
828 vcheckGLcall("glIntegerv");
829 glPixelZoom(1.0, -1.0);
830 vcheckGLcall("glPixelZoom");
832 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
833 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
834 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
836 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
837 vcheckGLcall("glRasterPos2f");
839 /* Some drivers(radeon dri, others?) don't like exceptions during
840 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
841 * after ReleaseDC. Reading it will cause an exception, which x11drv will
842 * catch to put the dib section in InSync mode, which leads to a crash
843 * and a blocked x server on my radeon card.
845 * The following lines read the dib section so it is put in inSync mode
846 * before glDrawPixels is called and the crash is prevented. There won't
847 * be any interfering gdi accesses, because UnlockRect is called from
848 * ReleaseDC, and the app won't use the dc any more afterwards.
850 if(This->Flags & SFLAG_DIBSECTION) {
852 read = This->resource.allocatedMemory[0];
855 switch (This->resource.format) {
856 /* No special care needed */
857 case WINED3DFMT_A4R4G4B4:
858 case WINED3DFMT_R5G6B5:
859 case WINED3DFMT_A1R5G5B5:
860 case WINED3DFMT_R8G8B8:
861 type = This->glDescription.glType;
862 fmt = This->glDescription.glFormat;
863 mem = This->resource.allocatedMemory;
864 bpp = This->bytesPerPixel;
867 case WINED3DFMT_X4R4G4B4:
870 unsigned short *data;
871 data = (unsigned short *)This->resource.allocatedMemory;
872 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
878 type = This->glDescription.glType;
879 fmt = This->glDescription.glFormat;
880 mem = This->resource.allocatedMemory;
881 bpp = This->bytesPerPixel;
885 case WINED3DFMT_X1R5G5B5:
888 unsigned short *data;
889 data = (unsigned short *)This->resource.allocatedMemory;
890 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
896 type = This->glDescription.glType;
897 fmt = This->glDescription.glFormat;
898 mem = This->resource.allocatedMemory;
899 bpp = This->bytesPerPixel;
903 case WINED3DFMT_X8R8G8B8:
905 /* make sure the X byte is set to alpha on, since it
906 could be any random value. This fixes the intro movie in Pirates! */
909 data = (unsigned int *)This->resource.allocatedMemory;
910 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
919 case WINED3DFMT_A8R8G8B8:
921 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
922 vcheckGLcall("glPixelStorei");
924 type = This->glDescription.glType;
925 fmt = This->glDescription.glFormat;
926 mem = This->resource.allocatedMemory;
927 bpp = This->bytesPerPixel;
931 case WINED3DFMT_A2R10G10B10:
933 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
934 vcheckGLcall("glPixelStorei");
936 type = This->glDescription.glType;
937 fmt = This->glDescription.glFormat;
938 mem = This->resource.allocatedMemory;
939 bpp = This->bytesPerPixel;
945 int height = This->glRect.bottom - This->glRect.top;
946 type = GL_UNSIGNED_BYTE;
949 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
951 ERR("Out of memory\n");
954 memory_allocated = TRUE;
955 d3dfmt_convert_surface(This->resource.allocatedMemory,
963 bpp = This->bytesPerPixel * 4;
969 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
972 type = This->glDescription.glType;
973 fmt = This->glDescription.glFormat;
974 mem = This->resource.allocatedMemory;
975 bpp = This->bytesPerPixel;
978 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
979 (This->lockedRect.bottom - This->lockedRect.top)-1,
981 mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
982 checkGLcall("glDrawPixels");
983 glPixelZoom(1.0,1.0);
984 vcheckGLcall("glPixelZoom");
986 glRasterPos3iv(&prev_rasterpos[0]);
987 vcheckGLcall("glRasterPos3iv");
989 /* Reset to previous pack row length */
990 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
991 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
993 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
994 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
997 /* Blitting environment requires that 2D texturing is enabled. It was turned off before,
1000 glEnable(GL_TEXTURE_2D);
1001 checkGLcall("glEnable(GL_TEXTURE_2D)");
1003 if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem);
1007 static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) {
1008 float glTexCoord[4];
1010 glTexCoord[0] = (float) This->lockedRect.left / (float) This->pow2Width; /* left */
1011 glTexCoord[1] = (float) This->lockedRect.right / (float) This->pow2Width; /* right */
1012 glTexCoord[2] = (float) This->lockedRect.top / (float) This->pow2Height; /* top */
1013 glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */
1015 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
1019 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1020 checkGLcall("glEnable glBindTexture");
1022 /* No filtering for blts */
1023 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1024 checkGLcall("glTexParameteri");
1025 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1026 checkGLcall("glTexParameteri");
1028 /* Start drawing a quad */
1031 glColor3d(1.0f, 1.0f, 1.0f);
1032 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1033 glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0);
1035 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1036 glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0);
1038 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1039 glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0);
1041 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1042 glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0);
1045 checkGLcall("glEnd");
1047 /* Unbind the texture */
1048 glBindTexture(GL_TEXTURE_2D, 0);
1049 checkGLcall("glEnable glBindTexture");
1054 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1055 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1056 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1057 IWineD3DSwapChainImpl *swapchain = NULL;
1059 if (!(This->Flags & SFLAG_LOCKED)) {
1060 WARN("trying to Unlock an unlocked surf@%p\n", This);
1061 return WINED3DERR_INVALIDCALL;
1064 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0);
1066 if (!(This->Flags & SFLAG_DIRTY)) {
1067 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1071 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1072 if(swapchain || iface == myDevice->render_targets[0]) {
1073 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1074 static BOOL warned = FALSE;
1076 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1079 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1083 /* Activate the correct context for the render target */
1085 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
1088 /* Primary offscreen render target */
1089 TRACE("Offscreen render target\n");
1090 glDrawBuffer(GL_BACK);
1091 checkGLcall("glDrawBuffer(GL_BACK)");
1093 if(iface == swapchain->frontBuffer) {
1094 TRACE("Onscreen front buffer\n");
1095 glDrawBuffer(GL_FRONT);
1096 checkGLcall("glDrawBuffer(GL_FRONT)");
1097 } else if(iface == swapchain->backBuffer[0]) {
1098 TRACE("Onscreen back buffer\n");
1099 glDrawBuffer(GL_BACK);
1100 checkGLcall("glDrawBuffer(GL_BACK)");
1102 FIXME("Unlocking a higher back buffer\n");
1103 glDrawBuffer(GL_BACK);
1104 checkGLcall("glDrawBuffer(GL_BACK)");
1106 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1109 switch(wined3d_settings.rendertargetlock_mode) {
1113 flush_to_framebuffer_drawpixels(This);
1118 flush_to_framebuffer_texture(This);
1121 if(!swapchain || swapchain->backBuffer) {
1122 glDrawBuffer(GL_BACK);
1123 checkGLcall("glDrawBuffer(GL_BACK)");
1125 glDrawBuffer(GL_FRONT);
1126 checkGLcall("glDrawBuffer(GL_FRONT)");
1130 /** restore clean dirty state */
1131 IWineD3DSurface_CleanDirtyRect(iface);
1132 } else if(iface == myDevice->stencilBufferTarget) {
1133 FIXME("Depth Stencil buffer locking is not implemented\n");
1135 /* The rest should be a normal texture */
1136 IWineD3DBaseTextureImpl *impl;
1137 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1138 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1139 * states need resetting
1141 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1142 if(impl->baseTexture.bindCount) {
1143 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1145 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1150 This->Flags &= ~SFLAG_LOCKED;
1151 memset(&This->lockedRect, 0, sizeof(RECT));
1155 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1156 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1157 WINED3DLOCKED_RECT lock;
1164 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1166 TRACE("(%p)->(%p)\n",This,pHDC);
1168 if(This->Flags & SFLAG_USERPTR) {
1169 ERR("Not supported on surfaces with an application-provided surfaces\n");
1173 /* Give more detailed info for ddraw */
1174 if (This->Flags & SFLAG_DCINUSE)
1175 return DDERR_DCALREADYCREATED;
1177 /* Can't GetDC if the surface is locked */
1178 if (This->Flags & SFLAG_LOCKED)
1179 return WINED3DERR_INVALIDCALL;
1181 memset(&lock, 0, sizeof(lock)); /* To be sure */
1183 /* Create a DIB section if there isn't a hdc yet */
1186 SYSTEM_INFO sysInfo;
1188 switch (This->bytesPerPixel) {
1191 /* Allocate extra space to store the RGB bit masks. */
1192 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1196 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1200 /* Allocate extra space for a palette. */
1201 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1202 sizeof(BITMAPINFOHEADER)
1204 * (1 << (This->bytesPerPixel * 8)));
1209 return E_OUTOFMEMORY;
1211 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1212 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1213 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1214 * add an extra line to the dib section
1216 GetSystemInfo(&sysInfo);
1217 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1219 TRACE("Adding an extra line to the dib section\n");
1222 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1223 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1224 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1225 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1226 b_info->bmiHeader.biPlanes = 1;
1227 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1229 b_info->bmiHeader.biXPelsPerMeter = 0;
1230 b_info->bmiHeader.biYPelsPerMeter = 0;
1231 b_info->bmiHeader.biClrUsed = 0;
1232 b_info->bmiHeader.biClrImportant = 0;
1234 /* Get the bit masks */
1235 masks = (DWORD *) &(b_info->bmiColors);
1236 switch (This->resource.format) {
1237 case WINED3DFMT_R8G8B8:
1238 usage = DIB_RGB_COLORS;
1239 b_info->bmiHeader.biCompression = BI_RGB;
1242 case WINED3DFMT_X1R5G5B5:
1243 case WINED3DFMT_A1R5G5B5:
1244 case WINED3DFMT_A4R4G4B4:
1245 case WINED3DFMT_X4R4G4B4:
1246 case WINED3DFMT_R3G3B2:
1247 case WINED3DFMT_A8R3G3B2:
1248 case WINED3DFMT_A2B10G10R10:
1249 case WINED3DFMT_A8B8G8R8:
1250 case WINED3DFMT_X8B8G8R8:
1251 case WINED3DFMT_A2R10G10B10:
1252 case WINED3DFMT_R5G6B5:
1253 case WINED3DFMT_A16B16G16R16:
1255 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1256 masks[0] = formatEntry->redMask;
1257 masks[1] = formatEntry->greenMask;
1258 masks[2] = formatEntry->blueMask;
1262 /* Don't know palette */
1263 b_info->bmiHeader.biCompression = BI_RGB;
1270 HeapFree(GetProcessHeap(), 0, b_info);
1271 return HRESULT_FROM_WIN32(GetLastError());
1274 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);
1275 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1278 if (!This->dib.DIBsection) {
1279 ERR("CreateDIBSection failed!\n");
1280 HeapFree(GetProcessHeap(), 0, b_info);
1281 return HRESULT_FROM_WIN32(GetLastError());
1284 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1286 /* copy the existing surface to the dib section */
1287 if(This->resource.allocatedMemory) {
1288 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1289 /* We won't need that any more */
1290 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1292 /* This is to make LockRect read the gl Texture although memory is allocated */
1293 This->Flags |= SFLAG_GLDIRTY;
1296 HeapFree(GetProcessHeap(), 0, b_info);
1298 /* Use the dib section from now on */
1299 This->resource.allocatedMemory = This->dib.bitmap_data;
1301 /* Now allocate a HDC */
1302 This->hDC = CreateCompatibleDC(0);
1303 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1304 TRACE("using wined3d palette %p\n", This->palette);
1305 SelectPalette(This->hDC,
1306 This->palette ? This->palette->hpal : 0,
1309 This->Flags |= SFLAG_DIBSECTION;
1312 /* Lock the surface */
1313 hr = IWineD3DSurface_LockRect(iface,
1318 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1319 /* keep the dib section */
1323 if(This->resource.format == WINED3DFMT_P8 ||
1324 This->resource.format == WINED3DFMT_A8P8) {
1327 PALETTEENTRY ent[256];
1329 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1330 for (n=0; n<256; n++) {
1331 col[n].rgbRed = ent[n].peRed;
1332 col[n].rgbGreen = ent[n].peGreen;
1333 col[n].rgbBlue = ent[n].peBlue;
1334 col[n].rgbReserved = 0;
1337 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1339 for (n=0; n<256; n++) {
1340 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1341 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1342 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1343 col[n].rgbReserved = 0;
1347 SetDIBColorTable(This->hDC, 0, 256, col);
1351 TRACE("returning %p\n",*pHDC);
1352 This->Flags |= SFLAG_DCINUSE;
1357 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1358 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1360 TRACE("(%p)->(%p)\n",This,hDC);
1362 if (!(This->Flags & SFLAG_DCINUSE))
1363 return WINED3DERR_INVALIDCALL;
1365 /* we locked first, so unlock now */
1366 IWineD3DSurface_UnlockRect(iface);
1368 This->Flags &= ~SFLAG_DCINUSE;
1373 /* ******************************************************
1374 IWineD3DSurface Internal (No mapping to directx api) parts follow
1375 ****************************************************** */
1377 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) {
1378 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1379 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1381 /* Default values: From the surface */
1382 *format = formatEntry->glFormat;
1383 *internal = formatEntry->glInternal;
1384 *type = formatEntry->glType;
1385 *convert = NO_CONVERSION;
1386 *target_bpp = This->bytesPerPixel;
1388 /* Ok, now look if we have to do any conversion */
1389 switch(This->resource.format) {
1394 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1395 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1397 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1399 *internal = GL_RGBA;
1400 *type = GL_UNSIGNED_BYTE;
1402 if(colorkey_active) {
1403 *convert = CONVERT_PALETTED_CK;
1405 *convert = CONVERT_PALETTED;
1411 case WINED3DFMT_R3G3B2:
1412 /* **********************
1413 GL_UNSIGNED_BYTE_3_3_2
1414 ********************** */
1415 if (colorkey_active) {
1416 /* This texture format will never be used.. So do not care about color keying
1417 up until the point in time it will be needed :-) */
1418 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1422 case WINED3DFMT_R5G6B5:
1423 if (colorkey_active) {
1424 *convert = CONVERT_CK_565;
1426 *internal = GL_RGBA;
1427 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1431 case WINED3DFMT_R8G8B8:
1432 if (colorkey_active) {
1433 *convert = CONVERT_CK_RGB24;
1435 *internal = GL_RGBA;
1436 *type = GL_UNSIGNED_INT_8_8_8_8;
1441 case WINED3DFMT_X8R8G8B8:
1442 if (colorkey_active) {
1443 *convert = CONVERT_RGB32_888;
1445 *internal = GL_RGBA;
1446 *type = GL_UNSIGNED_INT_8_8_8_8;
1450 case WINED3DFMT_V8U8:
1451 *convert = CONVERT_V8U8;
1453 *internal = GL_RGB8;
1465 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1466 BYTE *source, *dest;
1467 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1472 memcpy(dst, src, pitch * height);
1475 case CONVERT_PALETTED:
1476 case CONVERT_PALETTED_CK:
1478 IWineD3DPaletteImpl* pal = surf->palette;
1484 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1488 /* Still no palette? Use the device's palette */
1489 /* Get the surface's palette */
1490 for (i = 0; i < 256; i++) {
1491 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1493 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1494 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1495 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1496 if ((convert == CONVERT_PALETTED_CK) &&
1497 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1498 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1499 /* We should maybe here put a more 'neutral' color than the standard bright purple
1500 one often used by application to prevent the nice purple borders when bi-linear
1508 TRACE("Using surface palette %p\n", pal);
1509 /* Get the surface's palette */
1510 for (i = 0; i < 256; i++) {
1511 table[i][0] = pal->palents[i].peRed;
1512 table[i][1] = pal->palents[i].peGreen;
1513 table[i][2] = pal->palents[i].peBlue;
1514 if ((convert == CONVERT_PALETTED_CK) &&
1515 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1516 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1517 /* We should maybe here put a more 'neutral' color than the standard bright purple
1518 one often used by application to prevent the nice purple borders when bi-linear
1527 for (y = 0; y < height; y++)
1529 source = src + pitch * y;
1530 dest = dst + outpitch * y;
1531 /* This is an 1 bpp format, using the width here is fine */
1532 for (x = 0; x < width; x++) {
1533 BYTE color = *source++;
1534 *dest++ = table[color][0];
1535 *dest++ = table[color][1];
1536 *dest++ = table[color][2];
1537 *dest++ = table[color][3];
1543 case CONVERT_CK_565:
1545 /* Converting the 565 format in 5551 packed to emulate color-keying.
1547 Note : in all these conversion, it would be best to average the averaging
1548 pixels to get the color of the pixel that will be color-keyed to
1549 prevent 'color bleeding'. This will be done later on if ever it is
1552 Note2: Nvidia documents say that their driver does not support alpha + color keying
1553 on the same surface and disables color keying in such a case
1559 TRACE("Color keyed 565\n");
1561 for (y = 0; y < height; y++) {
1562 Source = (WORD *) (src + y * pitch);
1563 Dest = (WORD *) (dst + y * outpitch);
1564 for (x = 0; x < width; x++ ) {
1565 WORD color = *Source++;
1566 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1567 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1568 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1582 for(y = 0; y < height; y++) {
1583 Source = (short *) (src + y * pitch);
1584 Dest = (char *) (dst + y * outpitch);
1585 for (x = 0; x < width; x++ ) {
1586 long color = (*Source++);
1587 Dest[0] = color >> 8;
1597 ERR("Unsupported conversation type %d\n", convert);
1602 /* This function is used in case of 8bit paletted textures to upload the palette.
1603 For now it only supports GL_EXT_paletted_texture extension but support for other
1604 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1606 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1607 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1608 IWineD3DPaletteImpl* pal = This->palette;
1613 /* Still no palette? Use the device's palette */
1614 /* Get the surface's palette */
1615 for (i = 0; i < 256; i++) {
1616 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1618 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1619 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1620 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1621 if ((convert == CONVERT_PALETTED_CK) &&
1622 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1623 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1624 /* We should maybe here put a more 'neutral' color than the standard bright purple
1625 one often used by application to prevent the nice purple borders when bi-linear
1633 TRACE("Using surface palette %p\n", pal);
1634 /* Get the surface's palette */
1635 for (i = 0; i < 256; i++) {
1636 table[i][0] = pal->palents[i].peRed;
1637 table[i][1] = pal->palents[i].peGreen;
1638 table[i][2] = pal->palents[i].peBlue;
1639 if ((convert == CONVERT_PALETTED_CK) &&
1640 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1641 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1642 /* We should maybe here put a more 'neutral' color than the standard bright purple
1643 one often used by application to prevent the nice purple borders when bi-linear
1651 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1654 static BOOL palette9_changed(IWineD3DSurfaceImpl *This) {
1655 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1657 if(This->palette || (This->resource.format != WINED3DFMT_P8 && This->resource.format != WINED3DFMT_A8P8)) {
1658 /* If a ddraw-style palette is attached assume no d3d9 palette change.
1659 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
1664 if(This->palette9) {
1665 if(memcmp(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256) == 0) {
1669 This->palette9 = (PALETTEENTRY *) HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1671 memcpy(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
1675 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1676 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1677 GLenum format, internal, type;
1678 CONVERT_TYPES convert;
1680 int width, pitch, outpitch;
1683 if (This->Flags & SFLAG_INTEXTURE) {
1684 TRACE("Surface already in texture\n");
1687 if (This->Flags & SFLAG_DIRTY) {
1688 TRACE("Reloading because surface is dirty\n");
1689 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1690 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1691 /* Reload: vice versa OR */
1692 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1693 /* Also reload: Color key is active AND the color key has changed */
1694 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1695 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1696 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1697 TRACE("Reloading because of color keying\n");
1698 } else if(palette9_changed(This)) {
1699 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
1701 TRACE("surface isn't dirty\n");
1705 This->Flags &= ~SFLAG_DIRTY;
1707 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1708 * These resources are not bound by device size or format restrictions. Because of this,
1709 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1710 * However, these resources can always be created, locked, and copied.
1712 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1714 FIXME("(%p) Operation not supported for scratch textures\n",This);
1715 return WINED3DERR_INVALIDCALL;
1718 if (This->Flags & SFLAG_INPBUFFER) {
1719 if (This->glDescription.level != 0)
1720 FIXME("Surface in texture is only supported for level 0\n");
1721 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1722 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1723 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1724 This->resource.format == WINED3DFMT_DXT5)
1725 FIXME("Format %d not supported\n", This->resource.format);
1731 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1732 vcheckGLcall("glGetIntegerv");
1733 glReadBuffer(GL_BACK);
1734 vcheckGLcall("glReadBuffer");
1736 glCopyTexImage2D(This->glDescription.target,
1737 This->glDescription.level,
1738 This->glDescription.glFormatInternal,
1741 This->currentDesc.Width,
1742 This->currentDesc.Height,
1745 checkGLcall("glCopyTexImage2D");
1746 glReadBuffer(prevRead);
1747 vcheckGLcall("glReadBuffer");
1751 TRACE("Updating target %d\n", This->glDescription.target);
1752 This->Flags |= SFLAG_INTEXTURE;
1757 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1758 This->Flags |= SFLAG_GLCKEY;
1759 This->glCKey = This->SrcBltCKey;
1761 else This->Flags &= ~SFLAG_GLCKEY;
1763 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1765 /* The width is in 'length' not in bytes */
1766 width = This->currentDesc.Width;
1767 pitch = IWineD3DSurface_GetPitch(iface);
1769 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1770 int height = This->currentDesc.Height;
1772 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1773 outpitch = width * bpp;
1774 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1776 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1778 ERR("Out of memory %d, %d!\n", outpitch, height);
1779 return WINED3DERR_OUTOFVIDEOMEMORY;
1781 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1783 This->Flags |= SFLAG_CONVERTED;
1784 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1785 d3dfmt_p8_upload_palette(iface, convert);
1786 This->Flags &= ~SFLAG_CONVERTED;
1787 mem = This->resource.allocatedMemory;
1789 This->Flags &= ~SFLAG_CONVERTED;
1790 mem = This->resource.allocatedMemory;
1793 /* Make sure the correct pitch is used */
1794 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1796 if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1797 TRACE("non power of two support\n");
1798 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1800 surface_upload_data(This, This->currentDesc.Width, This->currentDesc.Height, format, type, mem);
1803 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1805 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1809 /* Restore the default pitch */
1810 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1812 if (mem != This->resource.allocatedMemory)
1813 HeapFree(GetProcessHeap(), 0, mem);
1817 static unsigned int gen = 0;
1820 if ((gen % 10) == 0) {
1821 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1822 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1825 * debugging crash code
1834 if (!(This->Flags & SFLAG_DONOTFREE)) {
1835 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1836 This->resource.allocatedMemory = NULL;
1844 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1847 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1848 char *allocatedMemory;
1850 IWineD3DSwapChain *swapChain = NULL;
1852 GLuint tmpTexture = 0;
1855 Textures my not be stored in ->allocatedgMemory and a GlTexture
1856 so we should lock the surface before saving a snapshot, or at least check that
1858 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1859 by calling GetTexImage and in compressed form by calling
1860 GetCompressedTexImageARB. Queried compressed images can be saved and
1861 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1862 texture images do not need to be processed by the GL and should
1863 significantly improve texture loading performance relative to uncompressed
1866 /* Setup the width and height to be the internal texture width and height. */
1867 width = This->pow2Width;
1868 height = This->pow2Height;
1869 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1870 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1872 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1873 /* we don't want to interfere with the back buffer so read the data into a temporary texture and then save the data out of the temporary texture */
1876 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1877 glEnable(GL_TEXTURE_2D);
1879 glGenTextures(1, &tmpTexture);
1880 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1882 glTexImage2D(GL_TEXTURE_2D,
1889 GL_UNSIGNED_INT_8_8_8_8_REV,
1892 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1893 vcheckGLcall("glGetIntegerv");
1894 glReadBuffer(GL_BACK);
1895 vcheckGLcall("glReadBuffer");
1896 glCopyTexImage2D(GL_TEXTURE_2D,
1905 checkGLcall("glCopyTexImage2D");
1906 glReadBuffer(prevRead);
1909 } else { /* bind the real texture */
1910 IWineD3DSurface_PreLoad(iface);
1912 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1914 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1915 glGetTexImage(GL_TEXTURE_2D,
1916 This->glDescription.level,
1918 GL_UNSIGNED_INT_8_8_8_8_REV,
1920 checkGLcall("glTexImage2D");
1922 glBindTexture(GL_TEXTURE_2D, 0);
1923 glDeleteTextures(1, &tmpTexture);
1927 f = fopen(filename, "w+");
1929 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1930 return WINED3DERR_INVALIDCALL;
1932 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1933 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1948 fwrite(&width,2,1,f);
1950 fwrite(&height,2,1,f);
1955 /* 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*/
1957 textureRow = allocatedMemory + (width * (height - 1) *4);
1959 textureRow = allocatedMemory;
1960 for (y = 0 ; y < height; y++) {
1961 for (i = 0; i < width; i++) {
1962 color = *((DWORD*)textureRow);
1963 fputc((color >> 16) & 0xFF, f); /* B */
1964 fputc((color >> 8) & 0xFF, f); /* G */
1965 fputc((color >> 0) & 0xFF, f); /* R */
1966 fputc((color >> 24) & 0xFF, f); /* A */
1969 /* take two rows of the pointer to the texture memory */
1971 (textureRow-= width << 3);
1974 TRACE("Closing file\n");
1978 IWineD3DSwapChain_Release(swapChain);
1980 HeapFree(GetProcessHeap(), 0, allocatedMemory);
1984 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
1985 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1986 This->Flags &= ~SFLAG_DIRTY;
1987 This->dirtyRect.left = This->currentDesc.Width;
1988 This->dirtyRect.top = This->currentDesc.Height;
1989 This->dirtyRect.right = 0;
1990 This->dirtyRect.bottom = 0;
1991 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
1992 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
1997 * Slightly inefficient way to handle multiple dirty rects but it works :)
1999 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2000 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2001 IWineD3DBaseTexture *baseTexture = NULL;
2002 This->Flags |= SFLAG_DIRTY;
2003 if (NULL != pDirtyRect) {
2004 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2005 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2006 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2007 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2009 This->dirtyRect.left = 0;
2010 This->dirtyRect.top = 0;
2011 This->dirtyRect.right = This->currentDesc.Width;
2012 This->dirtyRect.bottom = This->currentDesc.Height;
2014 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2015 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2016 /* if the container is a basetexture then mark it dirty. */
2017 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2018 TRACE("Passing to conatiner\n");
2019 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2020 IWineD3DBaseTexture_Release(baseTexture);
2025 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2026 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2028 TRACE("This %p, container %p\n", This, container);
2030 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2032 TRACE("Setting container to %p from %p\n", container, This->container);
2033 This->container = container;
2038 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2039 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2040 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2042 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2043 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2044 return WINED3DERR_INVALIDCALL;
2047 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2048 if (format == WINED3DFMT_UNKNOWN) {
2049 This->resource.size = 0;
2050 } else if (format == WINED3DFMT_DXT1) {
2051 /* DXT1 is half byte per pixel */
2052 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2054 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2055 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2056 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2058 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2059 This->resource.size *= This->pow2Height;
2063 /* Setup some glformat defaults */
2064 This->glDescription.glFormat = formatEntry->glFormat;
2065 This->glDescription.glFormatInternal = formatEntry->glInternal;
2066 This->glDescription.glType = formatEntry->glType;
2068 if (format != WINED3DFMT_UNKNOWN) {
2069 This->bytesPerPixel = formatEntry->bpp;
2071 This->bytesPerPixel = 0;
2074 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2076 This->resource.format = format;
2078 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);
2083 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2084 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2086 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2087 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2088 ERR("Not supported on render targets\n");
2089 return WINED3DERR_INVALIDCALL;
2092 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2093 WARN("Surface is locked or the HDC is in use\n");
2094 return WINED3DERR_INVALIDCALL;
2097 if(Mem && Mem != This->resource.allocatedMemory) {
2099 /* Do I have to copy the old surface content? */
2100 if(This->Flags & SFLAG_DIBSECTION) {
2101 /* Release the DC. No need to hold the critical section for the update
2102 * Thread because this thread runs only on front buffers, but this method
2103 * fails for render targets in the check above.
2105 SelectObject(This->hDC, This->dib.holdbitmap);
2106 DeleteDC(This->hDC);
2107 /* Release the DIB section */
2108 DeleteObject(This->dib.DIBsection);
2109 This->dib.bitmap_data = NULL;
2110 This->resource.allocatedMemory = NULL;
2112 This->Flags &= ~SFLAG_DIBSECTION;
2113 } else if(!(This->Flags & SFLAG_USERPTR)) {
2114 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2116 This->resource.allocatedMemory = Mem;
2117 This->Flags |= SFLAG_USERPTR;
2118 } else if(This->Flags & SFLAG_USERPTR) {
2119 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2120 This->resource.allocatedMemory = NULL;
2121 This->Flags &= ~SFLAG_USERPTR;
2126 /* TODO: replace this function with context management routines */
2127 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2128 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2131 This->Flags |= SFLAG_INPBUFFER;
2133 This->Flags &= ~SFLAG_INPBUFFER;
2137 This->Flags |= SFLAG_INTEXTURE;
2139 This->Flags &= ~SFLAG_INTEXTURE;
2145 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2146 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2147 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2148 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2150 /* Flipping is only supported on RenderTargets */
2151 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2154 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2155 * FIXME("(%p) Target override is not supported by now\n", This);
2156 * Additionally, it isn't really possible to support triple-buffering
2157 * properly on opengl at all
2161 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2162 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2165 /* Does a direct frame buffer -> texture copy. Stretching is done
2166 * with single pixel copy calls
2168 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2169 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2172 BOOL warned = FALSE; /* deliberately not static */
2173 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2177 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2179 /* Bind the target texture */
2180 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2181 checkGLcall("glBindTexture");
2182 if(!swapchain || (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0])) {
2183 glReadBuffer(GL_BACK);
2185 glReadBuffer(GL_FRONT);
2187 checkGLcall("glReadBuffer");
2189 xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
2190 yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
2192 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2193 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2197 !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) &&
2198 !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2199 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2201 glCopyTexSubImage2D(This->glDescription.target,
2202 This->glDescription.level,
2203 drect->x1, drect->y1, /* xoffset, yoffset */
2204 srect->x1, Src->currentDesc.Height - srect->y2,
2205 drect->x2 - drect->x1, drect->y2 - drect->y1);
2207 UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
2208 /* I have to process this row by row to swap the image,
2209 * otherwise it would be upside down, so streching in y direction
2210 * doesn't cost extra time
2212 * However, streching in x direction can be avoided if not necessary
2214 for(row = drect->y1; row < drect->y2; row++) {
2215 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2216 /* Well, that stuff works, but it's very slow.
2217 * find a better way instead
2223 FIXME("Doing a pixel by pixel render target -> texture copy, expect performance issues\n");
2226 for(col = drect->x1; col < drect->x2; col++) {
2227 glCopyTexSubImage2D(This->glDescription.target,
2228 This->glDescription.level,
2229 drect->x1 + col, row, /* xoffset, yoffset */
2230 srect->x1 + col * xrel, yoffset - (int) (row * yrel),
2234 glCopyTexSubImage2D(This->glDescription.target,
2235 This->glDescription.level,
2236 drect->x1, row, /* xoffset, yoffset */
2237 srect->x1, yoffset - (int) (row * yrel),
2238 drect->x2-drect->x1, 1);
2243 vcheckGLcall("glCopyTexSubImage2D");
2247 /* Uses the hardware to stretch and flip the image */
2248 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown) {
2250 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2251 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2252 float left, right, top, bottom; /* Texture coordinates */
2253 UINT fbwidth = Src->currentDesc.Width;
2254 UINT fbheight = Src->currentDesc.Height;
2256 TRACE("Using hwstretch blit\n");
2257 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2259 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2261 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2262 * we are reading from the back buffer, the backup can be used as source texture
2264 glGenTextures(1, &backup);
2265 checkGLcall("glGenTextures(1, &backup)");
2266 glBindTexture(GL_TEXTURE_2D, backup);
2267 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
2269 glReadBuffer(GL_BACK);
2270 checkGLcall("glReadBuffer(GL_BACK)");
2272 /* TODO: Only back up the part that will be overwritten */
2273 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2274 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2275 checkGLcall("glTexImage2D");
2277 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2278 0, 0 /* read offsets */,
2283 checkGLcall("glCopyTexSubImage2D");
2285 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2286 checkGLcall("glTexParameteri");
2287 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2288 checkGLcall("glTexParameteri");
2290 if(!swapchain || (IWineD3DSurface *) This == swapchain->backBuffer[0]) {
2293 glReadBuffer(GL_FRONT);
2294 checkGLcall("glReadBuffer(GL_FRONT)");
2296 glGenTextures(1, &src);
2297 checkGLcall("glGenTextures(1, &src)");
2298 glBindTexture(GL_TEXTURE_2D, src);
2299 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2301 /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2302 * out for power of 2 sizes
2304 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2305 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2306 checkGLcall("glTexImage2D");
2307 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2308 0, 0 /* read offsets */,
2313 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2314 checkGLcall("glTexParameteri");
2315 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2316 checkGLcall("glTexParameteri");
2318 glReadBuffer(GL_BACK);
2319 checkGLcall("glReadBuffer(GL_BACK)");
2321 checkGLcall("glEnd and previous");
2323 left = (float) srect->x1 / (float) Src->pow2Width;
2324 right = (float) srect->x2 / (float) Src->pow2Width;
2327 top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2328 bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2330 top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2331 bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2334 /* draw the source texture stretched and upside down. The correct surface is bound already */
2335 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2336 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2340 glTexCoord2f(left, bottom);
2341 glVertex2i(0, fbheight);
2344 glTexCoord2f(left, top);
2345 glVertex2i(0, fbheight - drect->y2 - drect->y1);
2348 glTexCoord2f(right, top);
2349 glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
2352 glTexCoord2f(right, bottom);
2353 glVertex2i(drect->x2 - drect->x1, fbheight);
2355 checkGLcall("glEnd and previous");
2357 /* Now read the stretched and upside down image into the destination texture */
2358 glBindTexture(This->glDescription.target, This->glDescription.textureName);
2359 checkGLcall("glBindTexture");
2360 glCopyTexSubImage2D(This->glDescription.target,
2362 drect->x1, drect->y1, /* xoffset, yoffset */
2363 0, 0, /* We blitted the image to the origin */
2364 drect->x2 - drect->x1, drect->y2 - drect->y1);
2365 checkGLcall("glCopyTexSubImage2D");
2367 /* Write the back buffer backup back */
2368 glBindTexture(GL_TEXTURE_2D, backup);
2369 checkGLcall("glBindTexture(GL_TEXTURE_2D, backup)");
2373 glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height);
2377 glTexCoord2f(0.0, 0.0);
2378 glVertex2i(0, fbheight);
2381 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0);
2382 glVertex2i(fbwidth, Src->currentDesc.Height);
2385 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
2386 glVertex2i(fbwidth, 0);
2391 glDeleteTextures(1, &src);
2392 checkGLcall("glDeleteTextures(1, &src)");
2394 glDeleteTextures(1, &backup);
2395 checkGLcall("glDeleteTextures(1, &backup)");
2399 /* Not called from the VTable */
2400 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2402 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2403 IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
2404 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2407 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2409 /* Get the swapchain. One of the surfaces has to be a primary surface */
2410 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
2411 if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
2413 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
2414 if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
2417 /* Early sort out of cases where no render target is used */
2418 if(!dstSwapchain && !srcSwapchain &&
2419 SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2420 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
2421 return WINED3DERR_INVALIDCALL;
2424 /* No destination color keying supported */
2425 if(Flags & (DDBLT_KEYDEST | DDBLT_KEYDESTOVERRIDE)) {
2426 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2427 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2428 return WINED3DERR_INVALIDCALL;
2432 rect.x1 = DestRect->left;
2433 rect.y1 = DestRect->top;
2434 rect.x2 = DestRect->right;
2435 rect.y2 = DestRect->bottom;
2439 rect.x2 = This->currentDesc.Width;
2440 rect.y2 = This->currentDesc.Height;
2443 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
2444 if(dstSwapchain && dstSwapchain == srcSwapchain) {
2445 /* Half-life does a Blt from the back buffer to the front buffer,
2446 * Full surface size, no flags... Use present instead
2449 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2451 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2452 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2459 /* Check the Destination rect and the surface sizes */
2461 (rect.x1 == 0) && (rect.y1 == 0) &&
2462 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2463 (This->currentDesc.Width == Src->currentDesc.Width) &&
2464 (This->currentDesc.Height == Src->currentDesc.Height)) {
2465 /* These flags are unimportant for the flag check, remove them */
2467 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2468 if( dstSwapchain->backBuffer && ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) &&
2469 SrcSurface == dstSwapchain->backBuffer[0] ) {
2471 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
2473 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2474 * take very long, while a flip is fast.
2475 * This applies to Half-Life, which does such Blts every time it finished
2476 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2477 * menu. This is also used by all apps when they do windowed rendering
2479 * The problem is that flipping is not really the same as copying. After a
2480 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2481 * untouched. Therefore it's necessary to override the swap effect
2482 * and to set it back after the flip.
2485 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2487 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2488 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2489 NULL, NULL, 0, NULL);
2491 dstSwapchain->presentParms.SwapEffect = orig_swap;
2498 TRACE("Unsupported blit between buffers on the same swapchain\n");
2499 return WINED3DERR_INVALIDCALL;
2500 } else if((dstSwapchain || This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) &&
2501 (srcSwapchain || SrcSurface == myDevice->render_targets[0]) ) {
2502 ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n");
2503 return WINED3DERR_INVALIDCALL;
2506 if(srcSwapchain || SrcSurface == myDevice->render_targets[0]) {
2507 /* Blit from render target to texture */
2509 BOOL upsideDown, stretchx;
2511 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2512 TRACE("Color keying not supported by frame buffer to texture blit\n");
2513 return WINED3DERR_INVALIDCALL;
2514 /* Destination color key is checked above */
2517 /* Call preload for the surface to make sure it isn't dirty */
2518 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2520 /* Make sure that the top pixel is always above the bottom pixel, and keep a seperate upside down flag
2521 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2524 if(SrcRect->top < SrcRect->bottom) {
2525 srect.y1 = SrcRect->top;
2526 srect.y2 = SrcRect->bottom;
2529 srect.y1 = SrcRect->bottom;
2530 srect.y2 = SrcRect->top;
2533 srect.x1 = SrcRect->left;
2534 srect.x2 = SrcRect->right;
2538 srect.x2 = Src->currentDesc.Width;
2539 srect.y2 = Src->currentDesc.Height;
2542 if(rect.x1 > rect.x2) {
2546 upsideDown = !upsideDown;
2549 TRACE("Reading from an offscreen target\n");
2550 upsideDown = !upsideDown;
2553 if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
2559 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2560 * flip the image nor scale it. If GL_EXT_framebuffer_blit is available it can be used(hopefully,
2561 * not implemented by now). Otherwise:
2563 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2564 * -> If the app wants a image width an unscaled width, copy it line per line
2565 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
2566 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2567 * back buffer. This is slower than reading line per line, thus not used for flipping
2568 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2571 if(FALSE /* GL_SUPPORT(EXT_FRAMEBUFFER_BLIT) */) {
2572 TRACE("Using GL_EXT_framebuffer_blit for copying\n");
2573 } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
2574 rect.y2 - rect.y1 > Src->currentDesc.Height) {
2575 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
2576 fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2578 TRACE("Using hardware stretching to flip / stretch the texture\n");
2579 fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown);
2582 if(!(This->Flags & SFLAG_DONOTFREE)) {
2583 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2584 This->resource.allocatedMemory = NULL;
2586 This->Flags |= SFLAG_GLDIRTY;
2591 /* Blit from offscreen surface to render target */
2592 float glTexCoord[4];
2593 DWORD oldCKeyFlags = Src->CKeyFlags;
2594 DDCOLORKEY oldBltCKey = This->SrcBltCKey;
2595 RECT SourceRectangle;
2598 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2601 SourceRectangle.left = SrcRect->left;
2602 SourceRectangle.right = SrcRect->right;
2603 SourceRectangle.top = SrcRect->top;
2604 SourceRectangle.bottom = SrcRect->bottom;
2606 SourceRectangle.left = 0;
2607 SourceRectangle.right = Src->currentDesc.Width;
2608 SourceRectangle.top = 0;
2609 SourceRectangle.bottom = Src->currentDesc.Height;
2612 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2613 /* Fall back to software */
2614 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2615 SourceRectangle.left, SourceRectangle.top,
2616 SourceRectangle.right, SourceRectangle.bottom);
2617 return WINED3DERR_INVALIDCALL;
2620 /* Color keying: Check if we have to do a color keyed blt,
2621 * and if not check if a color key is activated.
2623 * Just modify the color keying parameters in the surface and restore them afterwards
2624 * The surface keeps track of the color key last used to load the opengl surface.
2625 * PreLoad will catch the change to the flags and color key and reload if neccessary.
2627 if(Flags & DDBLT_KEYSRC) {
2628 /* Use color key from surface */
2629 } else if(Flags & DDBLT_KEYSRCOVERRIDE) {
2630 /* Use color key from DDBltFx */
2631 Src->CKeyFlags |= DDSD_CKSRCBLT;
2632 This->SrcBltCKey = DDBltFx->ddckSrcColorkey;
2634 /* Do not use color key */
2635 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2638 /* Now load the surface */
2639 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2643 /* Activate the destination context, set it up for blitting */
2644 ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
2646 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2647 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer) {
2648 TRACE("Drawing to front buffer\n");
2649 glDrawBuffer(GL_FRONT);
2650 checkGLcall("glDrawBuffer GL_FRONT");
2653 /* Bind the texture */
2654 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2655 checkGLcall("glBindTexture");
2657 /* No filtering for blts */
2658 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2660 checkGLcall("glTexParameteri");
2661 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2663 checkGLcall("glTexParameteri");
2664 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2665 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2666 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2667 checkGLcall("glTexEnvi");
2669 /* This is for color keying */
2670 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2671 glEnable(GL_ALPHA_TEST);
2672 checkGLcall("glEnable GL_ALPHA_TEST");
2673 glAlphaFunc(GL_NOTEQUAL, 0.0);
2674 checkGLcall("glAlphaFunc\n");
2676 glDisable(GL_ALPHA_TEST);
2677 checkGLcall("glDisable GL_ALPHA_TEST");
2680 /* Draw a textured quad
2684 glColor3d(1.0f, 1.0f, 1.0f);
2685 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2690 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2691 glVertex3f(rect.x1, rect.y2, 0.0);
2693 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2698 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2703 checkGLcall("glEnd");
2705 if(Flags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE)) {
2706 glDisable(GL_ALPHA_TEST);
2707 checkGLcall("glDisable(GL_ALPHA_TEST)");
2710 /* Unbind the texture */
2711 glBindTexture(GL_TEXTURE_2D, 0);
2712 checkGLcall("glEnable glBindTexture");
2714 if(This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && oldDraw == GL_BACK) {
2715 glDrawBuffer(oldDraw);
2717 /* Restore the color key parameters */
2718 Src->CKeyFlags = oldCKeyFlags;
2719 This->SrcBltCKey = oldBltCKey;
2723 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2724 This->Flags |= SFLAG_GLDIRTY;
2728 /* Source-Less Blit to render target */
2729 if (Flags & DDBLT_COLORFILL) {
2730 /* This is easy to handle for the D3D Device... */
2733 TRACE("Colorfill\n");
2735 /* The color as given in the Blt function is in the format of the frame-buffer...
2736 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2738 if (This->resource.format == WINED3DFMT_P8) {
2739 if (This->palette) {
2740 color = ((0xFF000000) |
2741 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2742 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2743 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2748 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2749 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2752 color = ((0xFF000000) |
2753 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2754 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2755 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2758 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2759 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2760 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2762 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2763 color = DDBltFx->u5.dwFillColor;
2766 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2767 return WINED3DERR_INVALIDCALL;
2770 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2771 if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) {
2772 glDrawBuffer(GL_BACK);
2773 checkGLcall("glDrawBuffer(GL_BACK)");
2774 } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) {
2775 glDrawBuffer(GL_FRONT);
2776 checkGLcall("glDrawBuffer(GL_FRONT)");
2777 } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2778 glDrawBuffer(GL_BACK);
2779 checkGLcall("glDrawBuffer(GL_BACK)");
2781 TRACE("Surface is higher back buffer, falling back to software\n");
2782 return WINED3DERR_INVALIDCALL;
2785 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2787 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2788 1 /* Number of rectangles */,
2790 WINED3DCLEAR_TARGET,
2795 /* Restore the original draw buffer */
2796 if(!dstSwapchain || (dstSwapchain->backBuffer && dstSwapchain->backBuffer[0])) {
2797 glDrawBuffer(GL_BACK);
2798 vcheckGLcall("glDrawBuffer");
2805 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
2806 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
2807 return WINED3DERR_INVALIDCALL;
2810 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2811 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2812 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2813 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2814 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2815 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2817 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair */
2818 if(myDevice->inScene &&
2819 (iface == myDevice->stencilBufferTarget ||
2820 (SrcSurface && SrcSurface == myDevice->stencilBufferTarget))) {
2821 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2822 return WINED3DERR_INVALIDCALL;
2825 /* Special cases for RenderTargets */
2826 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2827 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2828 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2831 /* For the rest call the X11 surface implementation.
2832 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2833 * other Blts are rather rare
2835 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2838 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2839 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2840 TRACE("(%p)->(%x)\n", This, Flags);
2845 case DDGBS_ISBLTDONE:
2849 return DDERR_INVALIDPARAMS;
2853 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2854 /* XXX: DDERR_INVALIDSURFACETYPE */
2856 TRACE("(%p)->(%08x)\n",iface,Flags);
2859 case DDGFS_ISFLIPDONE:
2863 return DDERR_INVALIDPARAMS;
2867 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2868 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2869 TRACE("(%p)\n", This);
2871 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2874 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2875 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2876 TRACE("(%p)\n", This);
2878 /* So far we don't lose anything :) */
2879 This->Flags &= ~SFLAG_LOST;
2883 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2884 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2885 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2886 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2887 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2889 if(myDevice->inScene &&
2890 (iface == myDevice->stencilBufferTarget ||
2891 (Source && Source == myDevice->stencilBufferTarget))) {
2892 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2893 return WINED3DERR_INVALIDCALL;
2896 /* Special cases for RenderTargets */
2897 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2898 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2900 RECT SrcRect, DstRect;
2904 SrcRect.left = rsrc->left;
2905 SrcRect.top= rsrc->top;
2906 SrcRect.bottom = rsrc->bottom;
2907 SrcRect.right = rsrc->right;
2911 SrcRect.right = srcImpl->currentDesc.Width;
2912 SrcRect.bottom = srcImpl->currentDesc.Height;
2915 DstRect.left = dstx;
2917 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2918 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2920 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2921 if(trans & DDBLTFAST_SRCCOLORKEY)
2922 Flags |= DDBLT_KEYSRC;
2923 if(trans & DDBLTFAST_DESTCOLORKEY)
2924 Flags |= DDBLT_KEYDEST;
2925 if(trans & DDBLTFAST_WAIT)
2926 Flags |= DDBLT_WAIT;
2927 if(trans & DDBLTFAST_DONOTWAIT)
2928 Flags |= DDBLT_DONOTWAIT;
2930 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2934 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2937 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2938 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2939 TRACE("(%p)->(%p)\n", This, Pal);
2941 *Pal = (IWineD3DPalette *) This->palette;
2945 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2946 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2948 IWineD3DPaletteImpl *pal = This->palette;
2950 TRACE("(%p)\n", This);
2952 if(This->resource.format == WINED3DFMT_P8 ||
2953 This->resource.format == WINED3DFMT_A8P8)
2955 TRACE("Dirtifying surface\n");
2956 This->Flags |= SFLAG_DIRTY;
2959 if(This->Flags & SFLAG_DIBSECTION) {
2960 TRACE("(%p): Updating the hdc's palette\n", This);
2961 for (n=0; n<256; n++) {
2963 col[n].rgbRed = pal->palents[n].peRed;
2964 col[n].rgbGreen = pal->palents[n].peGreen;
2965 col[n].rgbBlue = pal->palents[n].peBlue;
2967 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2968 /* Use the default device palette */
2969 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2970 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2971 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2973 col[n].rgbReserved = 0;
2975 SetDIBColorTable(This->hDC, 0, 256, col);
2981 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2982 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2983 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2984 TRACE("(%p)->(%p)\n", This, Pal);
2986 if(This->palette != NULL)
2987 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2988 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2990 if(PalImpl != NULL) {
2991 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2992 /* Set the device's main palette if the palette
2993 * wasn't a primary palette before
2995 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2996 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2999 for(i=0; i < 256; i++) {
3000 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
3004 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
3007 This->palette = PalImpl;
3009 return IWineD3DSurface_RealizePalette(iface);
3012 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
3013 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3014 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
3016 if ((Flags & DDCKEY_COLORSPACE) != 0) {
3017 FIXME(" colorkey value not supported (%08x) !\n", Flags);
3018 return DDERR_INVALIDPARAMS;
3021 /* Dirtify the surface, but only if a key was changed */
3023 switch (Flags & ~DDCKEY_COLORSPACE) {
3024 case DDCKEY_DESTBLT:
3025 This->DestBltCKey = *CKey;
3026 This->CKeyFlags |= DDSD_CKDESTBLT;
3029 case DDCKEY_DESTOVERLAY:
3030 This->DestOverlayCKey = *CKey;
3031 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
3034 case DDCKEY_SRCOVERLAY:
3035 This->SrcOverlayCKey = *CKey;
3036 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
3040 This->SrcBltCKey = *CKey;
3041 This->CKeyFlags |= DDSD_CKSRCBLT;
3046 switch (Flags & ~DDCKEY_COLORSPACE) {
3047 case DDCKEY_DESTBLT:
3048 This->CKeyFlags &= ~DDSD_CKDESTBLT;
3051 case DDCKEY_DESTOVERLAY:
3052 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
3055 case DDCKEY_SRCOVERLAY:
3056 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
3060 This->CKeyFlags &= ~DDSD_CKSRCBLT;
3068 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3069 /** Check against the maximum texture sizes supported by the video card **/
3070 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3072 TRACE("%p\n", This);
3073 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3074 /* one of three options
3075 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)
3076 2: Set the texture to the maxium size (bad idea)
3077 3: WARN and return WINED3DERR_NOTAVAILABLE;
3078 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.
3080 WARN("(%p) Creating an oversized surface\n", This);
3081 This->Flags |= SFLAG_OVERSIZE;
3083 /* This will be initialized on the first blt */
3084 This->glRect.left = 0;
3085 This->glRect.top = 0;
3086 This->glRect.right = 0;
3087 This->glRect.bottom = 0;
3089 /* No oversize, gl rect is the full texture size */
3090 This->Flags &= ~SFLAG_OVERSIZE;
3091 This->glRect.left = 0;
3092 This->glRect.top = 0;
3093 This->glRect.right = This->pow2Width;
3094 This->glRect.bottom = This->pow2Height;
3100 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3101 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3103 TRACE("(%p)\n", This);
3105 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3106 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3107 ie pitch = (width/4) * bytes per block */
3108 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3109 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3110 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3111 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3112 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3114 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3115 /* Surfaces are 32 bit aligned */
3116 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3118 TRACE("(%p) Returning %d\n", This, ret);
3122 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3123 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3125 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3127 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3129 TRACE("(%p): Not an overlay surface\n", This);
3130 return DDERR_NOTAOVERLAYSURFACE;
3136 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3137 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3139 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3141 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3143 TRACE("(%p): Not an overlay surface\n", This);
3144 return DDERR_NOTAOVERLAYSURFACE;
3150 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3151 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3152 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3154 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3156 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3158 TRACE("(%p): Not an overlay surface\n", This);
3159 return DDERR_NOTAOVERLAYSURFACE;
3165 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3166 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3167 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3168 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3170 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3172 TRACE("(%p): Not an overlay surface\n", This);
3173 return DDERR_NOTAOVERLAYSURFACE;
3179 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3182 IWineD3DSurfaceImpl_QueryInterface,
3183 IWineD3DSurfaceImpl_AddRef,
3184 IWineD3DSurfaceImpl_Release,
3185 /* IWineD3DResource */
3186 IWineD3DSurfaceImpl_GetParent,
3187 IWineD3DSurfaceImpl_GetDevice,
3188 IWineD3DSurfaceImpl_SetPrivateData,
3189 IWineD3DSurfaceImpl_GetPrivateData,
3190 IWineD3DSurfaceImpl_FreePrivateData,
3191 IWineD3DSurfaceImpl_SetPriority,
3192 IWineD3DSurfaceImpl_GetPriority,
3193 IWineD3DSurfaceImpl_PreLoad,
3194 IWineD3DSurfaceImpl_GetType,
3195 /* IWineD3DSurface */
3196 IWineD3DSurfaceImpl_GetContainer,
3197 IWineD3DSurfaceImpl_GetDesc,
3198 IWineD3DSurfaceImpl_LockRect,
3199 IWineD3DSurfaceImpl_UnlockRect,
3200 IWineD3DSurfaceImpl_GetDC,
3201 IWineD3DSurfaceImpl_ReleaseDC,
3202 IWineD3DSurfaceImpl_Flip,
3203 IWineD3DSurfaceImpl_Blt,
3204 IWineD3DSurfaceImpl_GetBltStatus,
3205 IWineD3DSurfaceImpl_GetFlipStatus,
3206 IWineD3DSurfaceImpl_IsLost,
3207 IWineD3DSurfaceImpl_Restore,
3208 IWineD3DSurfaceImpl_BltFast,
3209 IWineD3DSurfaceImpl_GetPalette,
3210 IWineD3DSurfaceImpl_SetPalette,
3211 IWineD3DSurfaceImpl_RealizePalette,
3212 IWineD3DSurfaceImpl_SetColorKey,
3213 IWineD3DSurfaceImpl_GetPitch,
3214 IWineD3DSurfaceImpl_SetMem,
3215 IWineD3DSurfaceImpl_SetOverlayPosition,
3216 IWineD3DSurfaceImpl_GetOverlayPosition,
3217 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3218 IWineD3DSurfaceImpl_UpdateOverlay,
3220 IWineD3DSurfaceImpl_CleanDirtyRect,
3221 IWineD3DSurfaceImpl_AddDirtyRect,
3222 IWineD3DSurfaceImpl_LoadTexture,
3223 IWineD3DSurfaceImpl_SaveSnapshot,
3224 IWineD3DSurfaceImpl_SetContainer,
3225 IWineD3DSurfaceImpl_SetPBufferState,
3226 IWineD3DSurfaceImpl_SetGlTextureDesc,
3227 IWineD3DSurfaceImpl_GetGlDesc,
3228 IWineD3DSurfaceImpl_GetData,
3229 IWineD3DSurfaceImpl_SetFormat,
3230 IWineD3DSurfaceImpl_PrivateSetup