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
50 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf);
52 /* *******************************************
53 IWineD3DSurface IUnknown parts follow
54 ******************************************* */
55 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
57 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
58 /* Warn ,but be nice about things */
59 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
61 ERR("Probably FIXME: Calling query interface with NULL riid\n");
63 if (IsEqualGUID(riid, &IID_IUnknown)
64 || IsEqualGUID(riid, &IID_IWineD3DBase)
65 || IsEqualGUID(riid, &IID_IWineD3DResource)
66 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
67 IUnknown_AddRef((IUnknown*)iface);
75 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
76 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
77 ULONG ref = InterlockedIncrement(&This->resource.ref);
78 TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
82 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
83 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
84 ULONG ref = InterlockedDecrement(&This->resource.ref);
85 TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
87 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
88 TRACE("(%p) : cleaning up\n", This);
89 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
91 TRACE("Deleting texture %d\n", This->glDescription.textureName);
92 glDeleteTextures(1, &This->glDescription.textureName);
96 if(This->Flags & SFLAG_DIBSECTION) {
98 SelectObject(This->hDC, This->dib.holdbitmap);
100 /* Release the DIB section */
101 DeleteObject(This->dib.DIBsection);
102 This->dib.bitmap_data = NULL;
103 This->resource.allocatedMemory = NULL;
105 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
107 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
108 if(iface == device->ddraw_primary)
109 device->ddraw_primary = NULL;
111 TRACE("(%p) Released\n", This);
112 HeapFree(GetProcessHeap(), 0, This);
118 /* ****************************************************
119 IWineD3DSurface IWineD3DResource parts follow
120 **************************************************** */
121 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
122 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
125 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
126 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
129 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
130 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
133 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
134 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
137 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
138 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
141 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
142 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
145 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
146 /* TODO: re-write the way textures and managed,
147 * use a 'opengl context manager' to manage RenderTarget surfaces
148 ** *********************************************************/
150 /* TODO: check for locks */
151 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
152 IWineD3DBaseTexture *baseTexture = NULL;
153 TRACE("(%p)Checking to see if the container is a base texture\n", This);
154 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
155 TRACE("Passing to conatiner\n");
156 IWineD3DBaseTexture_PreLoad(baseTexture);
157 IWineD3DBaseTexture_Release(baseTexture);
159 TRACE("(%p) : About to load surface\n", This);
161 #if 0 /* TODO: context manager support */
162 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
164 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
165 if (This->glDescription.level == 0 && This->glDescription.textureName == 0) {
166 glGenTextures(1, &This->glDescription.textureName);
167 checkGLcall("glGenTextures");
168 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
169 glBindTexture(This->glDescription.target, This->glDescription.textureName);
170 checkGLcall("glBindTexture");
171 IWineD3DSurface_LoadTexture(iface);
172 /* This is where we should be reducing the amount of GLMemoryUsed */
174 if (This->glDescription.level == 0) {
175 glBindTexture(This->glDescription.target, This->glDescription.textureName);
176 checkGLcall("glBindTexture");
177 IWineD3DSurface_LoadTexture(iface);
178 } else if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
179 /* assume this is a coding error not a real error for now */
180 FIXME("Mipmap surface has a glTexture bound to it!\n");
183 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
184 /* Tell opengl to try and keep this texture in video ram (well mostly) */
187 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
189 /* TODO: disable texture support, if it wastn't enabled when we entered. */
190 #if 0 /* TODO: context manager support */
191 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
192 /* we don't care when the state is disabled(if atall) */);
199 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
200 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
201 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
204 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
205 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
206 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
209 /* ******************************************************
210 IWineD3DSurface IWineD3DSurface parts follow
211 ****************************************************** */
213 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainerParent(IWineD3DSurface* iface, IUnknown **ppContainerParent) {
214 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
216 TRACE("(%p) : ppContainerParent %p)\n", This, ppContainerParent);
218 if (!ppContainerParent) {
219 ERR("(%p) : Called without a valid ppContainerParent.\n", This);
222 if (This->container) {
223 IWineD3DBase_GetParent(This->container, ppContainerParent);
224 if (!ppContainerParent) {
225 /* WineD3D objects should always have a parent */
226 ERR("(%p) : GetParent returned NULL\n", This);
228 IUnknown_Release(*ppContainerParent); /* GetParent adds a reference; we want just the pointer */
230 *ppContainerParent = NULL;
236 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
237 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
238 IWineD3DBase *container = 0;
240 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
243 ERR("Called without a valid ppContainer.\n");
247 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
248 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
249 * GetContainer will return the Direct3D device used to create the surface.
251 if (This->container) {
252 container = This->container;
254 container = (IWineD3DBase *)This->resource.wineD3DDevice;
257 TRACE("Relaying to QueryInterface\n");
258 return IUnknown_QueryInterface(container, riid, ppContainer);
261 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
262 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
264 TRACE("(%p) : copying into %p\n", This, pDesc);
265 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
266 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
267 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
268 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
269 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
270 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
271 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
272 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
273 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
277 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
278 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
279 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
280 if (This->glDescription.textureName == 0 && textureName != 0) {
281 This->Flags |= SFLAG_DIRTY;
282 IWineD3DSurface_AddDirtyRect(iface, NULL);
284 This->glDescription.textureName = textureName;
285 This->glDescription.target = target;
288 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
289 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
290 TRACE("(%p) : returning %p\n", This, &This->glDescription);
291 *glDescription = &This->glDescription;
294 /* TODO: think about moving this down to resource? */
295 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
296 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
297 /* 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 */
298 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
299 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
301 return (CONST void*)(This->resource.allocatedMemory);
304 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
310 switch(This->resource.format)
314 /* GL can't return palettized data, so read ARGB pixels into a
315 * seperate block of memory and convert them into palettized format
316 * in software. Slow, but if the app means to use palettized render
317 * targets and lock it...
319 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
320 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
321 * for the color channels when palettizing the colors.
324 type = GL_UNSIGNED_BYTE;
326 mem = HeapAlloc(GetProcessHeap(), 0, (rect->bottom - rect->top) * pitch);
328 ERR("Out of memory\n");
336 fmt = This->glDescription.glFormat;
337 type = This->glDescription.glType;
340 if (rect->left == 0 &&
341 rect->right == This->currentDesc.Width ) {
342 BYTE *row, *top, *bottom;
345 glReadPixels(0, rect->top,
346 This->currentDesc.Width,
347 rect->bottom - rect->top,
352 /* glReadPixels returns the image upside down, and there is no way to prevent this.
353 Flip the lines in software */
354 row = HeapAlloc(GetProcessHeap(), 0, pitch);
356 ERR("Out of memory\n");
360 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
361 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
362 memcpy(row, top, pitch);
363 memcpy(top, bottom, pitch);
364 memcpy(bottom, row, pitch);
368 HeapFree(GetProcessHeap(), 0, row);
370 if(This->lockedRect.top == 0 && This->lockedRect.bottom == This->currentDesc.Height) {
371 This->Flags &= ~SFLAG_GLDIRTY;
374 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
375 glReadPixels(rect->left,
376 rect->bottom - j - 1,
377 rect->right - rect->left,
381 (char *)mem + (pitch * (j-rect->top)));
385 vcheckGLcall("glReadPixels");
387 if(This->resource.format == WINED3DFMT_P8) {
389 DWORD width = pitch / 3;
392 pal = This->palette->palents;
394 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
397 for(y = rect->top; y < rect->bottom; y++) {
398 for(x = rect->left; x < rect->right; x++) {
399 /* start lines pixels */
400 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
401 BYTE *green = blue + 1;
402 BYTE *red = green + 1;
404 for(c = 0; c < 256; c++) {
405 if(*red == pal[c].peRed &&
406 *green == pal[c].peGreen &&
407 *blue == pal[c].peBlue)
409 *((BYTE *) dest + y * width + x) = c;
415 HeapFree(GetProcessHeap(), 0, mem);
419 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
420 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
421 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
422 IWineD3DSwapChainImpl *swapchain = NULL;
423 static UINT messages = 0; /* holds flags to disable fixme messages */
424 BOOL backbuf = FALSE;
426 /* fixme: should we really lock as such? */
427 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
428 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
429 FIXME("Warning: Surface is in texture memory or pbuffer\n");
430 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
433 if (!(This->Flags & SFLAG_LOCKABLE)) {
434 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
435 texture regions, and since the destination is an unlockable region we need
437 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
438 /*return WINED3DERR_INVALIDCALL; */
441 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
442 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
444 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
445 if(swapchain != NULL) {
447 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
448 if(iface == swapchain->backBuffer[i]) {
455 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
456 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
457 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
458 } else if (iface == myDevice->renderTarget) {
459 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
460 } else if (iface == myDevice->depthStencilBuffer) {
461 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
464 if (NULL != swapchain) {
465 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
470 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
473 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
476 pLockedRect->pBits = This->resource.allocatedMemory;
477 This->lockedRect.left = 0;
478 This->lockedRect.top = 0;
479 This->lockedRect.right = This->currentDesc.Width;
480 This->lockedRect.bottom = This->currentDesc.Height;
481 TRACE("Locked Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
483 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
485 if ((pRect->top < 0) ||
487 (pRect->left >= pRect->right) ||
488 (pRect->top >= pRect->bottom) ||
489 (pRect->right > This->currentDesc.Width) ||
490 (pRect->bottom > This->currentDesc.Height))
492 WARN(" Invalid values in pRect !!!\n");
493 return D3DERR_INVALIDCALL;
496 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
497 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
499 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
501 This->lockedRect.left = pRect->left;
502 This->lockedRect.top = pRect->top;
503 This->lockedRect.right = pRect->right;
504 This->lockedRect.bottom = pRect->bottom;
507 if (This->Flags & SFLAG_NONPOW2) {
508 TRACE("Locking non-power 2 texture\n");
511 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
512 /* classic surface TODO: non 2d surfaces?
513 These resources may be POOL_SYSTEMMEM, so they must not access the device */
514 TRACE("locking an ordinarary surface\n");
515 /* Check to see if memory has already been allocated from the surface*/
516 if ((NULL == This->resource.allocatedMemory) ||
517 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
518 /* Non-system memory surfaces */
520 This->Flags &= ~SFLAG_GLDIRTY;
522 /*Surface has no memory currently allocated to it!*/
523 TRACE("(%p) Locking rect\n" , This);
524 if(!This->resource.allocatedMemory) {
525 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
527 if (0 != This->glDescription.textureName) {
528 /* Now I have to copy thing bits back */
529 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
530 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
533 /* Make sure that the texture is loaded */
534 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
536 TRACE("(%p) glGetTexImage level(%d), fmt(%d), typ(%d), mem(%p)\n" , This, This->glDescription.level, This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
538 if (This->resource.format == WINED3DFMT_DXT1 ||
539 This->resource.format == WINED3DFMT_DXT2 ||
540 This->resource.format == WINED3DFMT_DXT3 ||
541 This->resource.format == WINED3DFMT_DXT4 ||
542 This->resource.format == WINED3DFMT_DXT5) {
543 TRACE("Locking a compressed texture\n");
544 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
545 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
546 This->glDescription.level,
547 This->resource.allocatedMemory);
550 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
553 glGetTexImage(This->glDescription.target,
554 This->glDescription.level,
555 This->glDescription.glFormat,
556 This->glDescription.glType,
557 This->resource.allocatedMemory);
558 vcheckGLcall("glGetTexImage");
559 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
560 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
561 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
562 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
566 instead of boxing the texture :
567 |<-texture width ->| -->pow2width| /\
568 |111111111111111111| | |
569 |222 Texture 222222| boxed empty | texture height
570 |3333 Data 33333333| | |
571 |444444444444444444| | \/
572 ----------------------------------- |
573 | boxed empty | boxed empty | pow2height
575 -----------------------------------
578 were repacking the data to the expected texture width
580 |<-texture width ->| -->pow2width| /\
581 |111111111111111111222222222222222| |
582 |222333333333333333333444444444444| texture height
588 -----------------------------------
592 |<-texture width ->| /\
594 |222222222222222222|texture height
596 |444444444444444444| \/
599 this also means that any references to allocatedMemory should work with the data as if were a standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
601 internally the texture is still stored in a boxed format so any references to textureName will get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
603 if (This->Flags & SFLAG_NONPOW2) {
605 int pitcha = 0, pitchb = 0;
607 pitcha = This->bytesPerPixel * This->currentDesc.Width;
608 pitchb = This->bytesPerPixel * This->pow2Width;
609 datab = dataa = This->resource.allocatedMemory;
610 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
611 for (y = 1 ; y < This->currentDesc.Height; y++) {
612 dataa += pitcha; /* skip the first row */
614 memcpy(dataa, datab, pitcha);
621 } else { /* Nothing to do */
622 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
626 pLockedRect->pBits = This->resource.allocatedMemory;
628 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
629 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
631 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
635 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
636 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
639 BOOL notInContext = FALSE;
640 IWineD3DSwapChainImpl *targetSwapChain = NULL;
646 * for render->surface copy begin to begin of allocatedMemory
647 * unlock can be more easy
650 TRACE("locking a render target\n");
652 if (This->resource.allocatedMemory == NULL)
653 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
655 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
656 pLockedRect->pBits = This->resource.allocatedMemory;
659 vcheckGLcall("glFlush");
660 glGetIntegerv(GL_READ_BUFFER, &prev_read);
661 vcheckGLcall("glIntegerv");
662 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
663 vcheckGLcall("glIntegerv");
665 /* Here's what we have to do:
666 See if the swapchain has the same context as the renderTarget or the surface is the render target.
667 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
668 and use the front back buffer as required.
669 if not, we need to switch contexts and then switchback at the end.
671 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
672 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
674 /* NOTE: In a shared context environment the renderTarget will use the same context as the implicit swapchain (we're not in a shared environment yet! */
675 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
676 if (swapchain && iface == swapchain->frontBuffer) {
677 TRACE("locking front\n");
678 glReadBuffer(GL_FRONT);
680 else if (iface == myDevice->renderTarget || backbuf) {
681 TRACE("locking back buffer\n");
682 glReadBuffer(GL_BACK);
683 } else if (iface == myDevice->depthStencilBuffer) {
684 FIXME("Stencil Buffer lock unsupported for now\n");
686 FIXME("(%p) Shouldn't have got here!\n", This);
687 glReadBuffer(GL_BACK);
689 } else if (swapchain != NULL) {
690 IWineD3DSwapChainImpl *implSwapChain;
691 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
692 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
693 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
695 glReadBuffer(GL_BACK);
696 } else if (iface == swapchain->frontBuffer) {
697 glReadBuffer(GL_FRONT);
698 } else if (iface == myDevice->depthStencilBuffer) {
699 FIXME("Stencil Buffer lock unsupported for now\n");
701 FIXME("Should have got here!\n");
702 glReadBuffer(GL_BACK);
705 /* We need to switch contexts to be able to read the buffer!!! */
706 FIXME("The buffer requested isn't in the current openGL context\n");
708 /* TODO: check the contexts, to see if were shared with the current context */
710 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
712 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
713 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
715 /** the depth stencil in openGL has a format of GL_FLOAT
716 * which should be good for WINED3DFMT_D16_LOCKABLE
718 * it is unclear what format the stencil buffer is in except.
719 * 'Each index is converted to fixed point...
720 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
721 * mappings in the table GL_PIXEL_MAP_S_TO_S.
722 * glReadPixels(This->lockedRect.left,
723 * This->lockedRect.bottom - j - 1,
724 * This->lockedRect.right - This->lockedRect.left,
726 * GL_DEPTH_COMPONENT,
728 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
729 *****************************************/
730 if (!notInContext) { /* Only read the buffer if it's in the current context */
731 switch(wined3d_settings.rendertargetlock_mode) {
735 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
740 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
741 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
746 static BOOL warned = FALSE;
748 ERR("Application tries to lock the render target, but render target locking is disabled\n");
755 TRACE("Resetting buffer\n");
757 glReadBuffer(prev_read);
758 vcheckGLcall("glReadBuffer");
762 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
765 FIXME("TODO stencil depth surface locking surf%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
768 glReadPixels(This->lockedRect.left,
769 This->lockedRect.bottom - j - 1,
770 This->lockedRect.right - This->lockedRect.left,
772 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
779 FIXME("unsupported locking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
782 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
785 IWineD3DBaseTexture *pBaseTexture;
788 * as seen in msdn docs
790 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
792 /** Dirtify Container if needed */
793 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
794 TRACE("Making container dirty\n");
795 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
796 IWineD3DBaseTexture_Release(pBaseTexture);
798 TRACE("Surface is standalone, no need to dirty the container\n");
802 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
804 This->Flags |= SFLAG_LOCKED;
808 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
810 GLint prev_rasterpos[4];
812 BOOL storechanged = FALSE;
816 glDisable(GL_TEXTURE_2D);
817 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
818 glDisable(GL_TEXTURE_1D);
819 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
822 vcheckGLcall("glFlush");
823 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
824 vcheckGLcall("glIntegerv");
825 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
826 vcheckGLcall("glIntegerv");
827 glPixelZoom(1.0, -1.0);
828 vcheckGLcall("glPixelZoom");
830 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
831 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
832 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
834 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
835 vcheckGLcall("glRasterPos2f");
837 /* Some drivers(radeon dri, others?) don't like exceptions during
838 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
839 * after ReleaseDC. Reading it will cause an exception, which x11drv will
840 * catch to put the dib section in InSync mode, which leads to a crash
841 * and a blocked x server on my radeon card.
843 * The following lines read the dib section so it is put in inSync mode
844 * before glDrawPixels is called and the crash is prevented. There won't
845 * be any interfering gdi accesses, because UnlockRect is called from
846 * ReleaseDC, and the app won't use the dc any more afterwards.
848 if(This->Flags & SFLAG_DIBSECTION) {
850 read = This->resource.allocatedMemory[0];
853 switch (This->resource.format) {
854 /* No special care needed */
855 case WINED3DFMT_A4R4G4B4:
856 case WINED3DFMT_R5G6B5:
857 case WINED3DFMT_A1R5G5B5:
858 case WINED3DFMT_R8G8B8:
859 type = This->glDescription.glType;
860 fmt = This->glDescription.glFormat;
861 mem = This->resource.allocatedMemory;
864 case WINED3DFMT_X4R4G4B4:
867 unsigned short *data;
868 data = (unsigned short *)This->resource.allocatedMemory;
869 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
875 type = This->glDescription.glType;
876 fmt = This->glDescription.glFormat;
877 mem = This->resource.allocatedMemory;
881 case WINED3DFMT_X1R5G5B5:
884 unsigned short *data;
885 data = (unsigned short *)This->resource.allocatedMemory;
886 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
892 type = This->glDescription.glType;
893 fmt = This->glDescription.glFormat;
894 mem = This->resource.allocatedMemory;
898 case WINED3DFMT_X8R8G8B8:
900 /* make sure the X byte is set to alpha on, since it
901 could be any random value this fixes the intro move in Pirates! */
904 data = (unsigned int *)This->resource.allocatedMemory;
905 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
914 case WINED3DFMT_A8R8G8B8:
916 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
917 vcheckGLcall("glPixelStorei");
919 type = This->glDescription.glType;
920 fmt = This->glDescription.glFormat;
921 mem = This->resource.allocatedMemory;
925 case WINED3DFMT_A2R10G10B10:
927 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
928 vcheckGLcall("glPixelStorei");
930 type = This->glDescription.glType;
931 fmt = This->glDescription.glFormat;
932 mem = This->resource.allocatedMemory;
938 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
939 int height = This->glRect.bottom - This->glRect.top;
940 type = GL_UNSIGNED_BYTE;
943 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
945 ERR("Out of memory\n");
948 d3dfmt_convert_surface(This->resource.allocatedMemory,
957 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
960 type = This->glDescription.glType;
961 fmt = This->glDescription.glFormat;
962 mem = This->resource.allocatedMemory;
965 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
966 (This->lockedRect.bottom - This->lockedRect.top)-1,
969 checkGLcall("glDrawPixels");
970 glPixelZoom(1.0,1.0);
971 vcheckGLcall("glPixelZoom");
973 glRasterPos3iv(&prev_rasterpos[0]);
974 vcheckGLcall("glRasterPos3iv");
976 /* Reset to previous pack row length */
977 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
978 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
980 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
981 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
984 if(mem != This->resource.allocatedMemory) HeapFree(GetProcessHeap(), 0, mem);
988 static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
989 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
992 glTexCoord[0] = 0.0; /* left */
993 glTexCoord[1] = (float) This->currentDesc.Width / (float) This->pow2Width; /* right */
994 glTexCoord[2] = 0.0; /* top */
995 glTexCoord[3] = (float) This->currentDesc.Height / (float) This->pow2Height; /* bottom */
997 IWineD3DSurface_PreLoad(iface);
1001 /* Disable some fancy graphics effects */
1002 glDisable(GL_LIGHTING);
1003 checkGLcall("glDisable GL_LIGHTING");
1004 glDisable(GL_DEPTH_TEST);
1005 checkGLcall("glDisable GL_DEPTH_TEST");
1007 checkGLcall("glDisable GL_FOG");
1008 glDisable(GL_CULL_FACE);
1009 checkGLcall("glDisable GL_CULL_FACE");
1010 glDisable(GL_BLEND);
1011 checkGLcall("glDisable GL_BLEND");
1012 glDisable(GL_STENCIL_TEST);
1013 checkGLcall("glDisable GL_STENCIL_TEST");
1015 glEnable(GL_TEXTURE_2D);
1016 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1017 checkGLcall("glEnable glBindTexture");
1019 /* No filtering for blts */
1020 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1021 checkGLcall("glTexParameteri");
1022 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1023 checkGLcall("glTexParameteri");
1025 /* Start drawing a quad */
1028 glColor3d(1.0f, 1.0f, 1.0f);
1029 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1030 glVertex3f(0, 0, 0.0);
1032 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1033 glVertex3f(0, This->currentDesc.Height, 0.0);
1035 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1036 glVertex3d(This->currentDesc.Width, This->currentDesc.Height, 0.0);
1038 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1039 glVertex3f(This->currentDesc.Width, 0, 0.0);
1042 checkGLcall("glEnd");
1044 /* Unbind the texture */
1045 glBindTexture(GL_TEXTURE_2D, 0);
1046 checkGLcall("glEnable glBindTexture");
1051 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1052 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1053 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1054 const char *buffername = "";
1055 IWineD3DSwapChainImpl *swapchain = NULL;
1056 BOOL backbuf = FALSE;
1058 if (!(This->Flags & SFLAG_LOCKED)) {
1059 WARN("trying to Unlock an unlocked surf@%p\n", This);
1060 return WINED3DERR_INVALIDCALL;
1063 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
1064 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1068 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
1069 if(iface == swapchain->backBuffer[i]) {
1077 buffername = "backBuffer";
1078 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
1079 buffername = "frontBuffer";
1080 } else if (iface == myDevice->depthStencilBuffer) {
1081 buffername = "depthStencilBuffer";
1082 } else if (iface == myDevice->renderTarget) {
1083 buffername = "renderTarget";
1087 if (swapchain != NULL) {
1088 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1091 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
1093 if (!(This->Flags & SFLAG_DIRTY)) {
1094 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1098 if (0 == This->resource.usage) { /* classic surface */
1101 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
1103 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
1105 /****************************
1106 * TODO: Render targets are 'special' and
1107 * ?some? locking needs to be passed onto the context manager
1108 * so that it becomes possible to use auxiliary buffers, pbuffers
1109 * render-to-texture, shared, cached contexts etc...
1110 * ****************************/
1111 IWineD3DSwapChainImpl *implSwapChain;
1112 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
1114 if (backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
1119 /* glDrawPixels transforms the raster position as though it was a vertex -
1120 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1121 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1122 d3ddevice_set_ortho(This->resource.wineD3DDevice);
1124 if (iface == implSwapChain->frontBuffer) {
1125 glDrawBuffer(GL_FRONT);
1126 checkGLcall("glDrawBuffer GL_FRONT");
1127 } else if (backbuf || iface == myDevice->renderTarget) {
1128 glDrawBuffer(GL_BACK);
1129 checkGLcall("glDrawBuffer GL_BACK");
1132 /* Disable higher textures before calling glDrawPixels */
1133 for(tex = 1; tex < GL_LIMITS(samplers); tex++) {
1134 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1135 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + tex));
1136 checkGLcall("glActiveTextureARB");
1138 glDisable(GL_TEXTURE_2D);
1139 checkGLcall("glDisable GL_TEXTURE_2D");
1140 glDisable(GL_TEXTURE_1D);
1141 checkGLcall("glDisable GL_TEXTURE_1D");
1143 /* Activate texture 0, but don't disable it necessarilly */
1144 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1145 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1146 checkGLcall("glActiveTextureARB");
1149 /* And back buffers are not blended. Disable the depth test,
1150 that helps performance */
1151 glDisable(GL_BLEND);
1152 glDisable(GL_DEPTH_TEST);
1155 switch(wined3d_settings.rendertargetlock_mode) {
1159 flush_to_framebuffer_drawpixels(This);
1164 flush_to_framebuffer_texture(iface);
1169 static BOOL warned = FALSE;
1171 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1178 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1179 glDrawBuffer(GL_BACK);
1180 vcheckGLcall("glDrawBuffer");
1182 if(myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_TRUE ||
1183 myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_USEW) glEnable(GL_DEPTH_TEST);
1184 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1185 if (myDevice->stateBlock->renderState[D3DRS_FOGENABLE]) glEnable(GL_FOG);
1189 /** restore clean dirty state */
1190 IWineD3DSurface_CleanDirtyRect(iface);
1193 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1195 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1197 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1199 if (iface == myDevice->depthStencilBuffer) {
1200 FIXME("TODO stencil depth surface unlocking surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1202 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1206 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1210 This->Flags &= ~SFLAG_LOCKED;
1211 memset(&This->lockedRect, 0, sizeof(RECT));
1215 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1216 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1217 WINED3DLOCKED_RECT lock;
1224 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1226 TRACE("(%p)->(%p)\n",This,pHDC);
1228 if(This->Flags & SFLAG_USERPTR) {
1229 ERR("Not supported on surfaces with an application-provided surfaces\n");
1233 /* Give more detailed info for ddraw */
1234 if (This->Flags & SFLAG_DCINUSE)
1235 return DDERR_DCALREADYCREATED;
1237 /* Can't GetDC if the surface is locked */
1238 if (This->Flags & SFLAG_LOCKED)
1239 return WINED3DERR_INVALIDCALL;
1241 memset(&lock, 0, sizeof(lock)); /* To be sure */
1243 /* Create a DIB section if there isn't a hdc yet */
1246 SYSTEM_INFO sysInfo;
1248 if(This->Flags & SFLAG_ACTIVELOCK) {
1249 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1252 switch (This->bytesPerPixel) {
1255 /* Allocate extra space to store the RGB bit masks. */
1256 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1260 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1264 /* Allocate extra space for a palette. */
1265 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1266 sizeof(BITMAPINFOHEADER)
1268 * (1 << (This->bytesPerPixel * 8)));
1272 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1273 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1274 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1275 * add an extra line to the dib section
1277 GetSystemInfo(&sysInfo);
1278 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1280 TRACE("Adding an extra line to the dib section\n");
1283 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1284 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1285 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1286 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1287 b_info->bmiHeader.biSizeImage = This->currentDesc.Width * This->currentDesc.Height * This->bytesPerPixel;
1288 /* Use the full pow2 image size(assigned below) because LockRect
1289 * will need it for a full glGetTexImage call
1292 b_info->bmiHeader.biWidth = This->pow2Width;
1293 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1294 b_info->bmiHeader.biSizeImage = This->resource.size;
1296 b_info->bmiHeader.biPlanes = 1;
1297 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1299 b_info->bmiHeader.biXPelsPerMeter = 0;
1300 b_info->bmiHeader.biYPelsPerMeter = 0;
1301 b_info->bmiHeader.biClrUsed = 0;
1302 b_info->bmiHeader.biClrImportant = 0;
1304 /* Get the bit masks */
1305 masks = (DWORD *) &(b_info->bmiColors);
1306 switch (This->resource.format) {
1307 case WINED3DFMT_R8G8B8:
1308 usage = DIB_RGB_COLORS;
1309 b_info->bmiHeader.biCompression = BI_RGB;
1312 case WINED3DFMT_X1R5G5B5:
1313 case WINED3DFMT_A1R5G5B5:
1314 case WINED3DFMT_A4R4G4B4:
1315 case WINED3DFMT_X4R4G4B4:
1316 case WINED3DFMT_R3G3B2:
1317 case WINED3DFMT_A8R3G3B2:
1318 case WINED3DFMT_A2B10G10R10:
1319 case WINED3DFMT_A8B8G8R8:
1320 case WINED3DFMT_X8B8G8R8:
1321 case WINED3DFMT_A2R10G10B10:
1322 case WINED3DFMT_R5G6B5:
1323 case WINED3DFMT_A16B16G16R16:
1325 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1326 masks[0] = formatEntry->redMask;
1327 masks[1] = formatEntry->greenMask;
1328 masks[2] = formatEntry->blueMask;
1332 /* Don't know palette */
1333 b_info->bmiHeader.biCompression = BI_RGB;
1338 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1340 HeapFree(GetProcessHeap(), 0, b_info);
1341 return HRESULT_FROM_WIN32(GetLastError());
1344 TRACE("Creating a DIB section with size %ldx%ldx%d, size=%ld\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
1345 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1348 if (!This->dib.DIBsection) {
1349 ERR("CreateDIBSection failed!\n");
1350 return HRESULT_FROM_WIN32(GetLastError());
1352 HeapFree(GetProcessHeap(), 0, b_info);
1354 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1356 /* copy the existing surface to the dib section */
1357 if(This->resource.allocatedMemory) {
1358 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1359 /* We won't need that any more */
1360 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1362 /* This is to make LockRect read the gl Texture although memory is allocated */
1363 This->Flags |= SFLAG_GLDIRTY;
1366 /* Use the dib section from now on */
1367 This->resource.allocatedMemory = This->dib.bitmap_data;
1369 /* Now allocate a HDC */
1370 This->hDC = CreateCompatibleDC(0);
1371 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1372 TRACE("using wined3d palette %p\n", This->palette);
1373 SelectPalette(This->hDC,
1374 This->palette ? This->palette->hpal : 0,
1377 This->Flags |= SFLAG_DIBSECTION;
1380 /* Lock the surface */
1381 hr = IWineD3DSurface_LockRect(iface,
1386 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1387 /* keep the dib section */
1391 if(This->resource.format == WINED3DFMT_P8 ||
1392 This->resource.format == WINED3DFMT_A8P8) {
1395 PALETTEENTRY ent[256];
1397 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1398 for (n=0; n<256; n++) {
1399 col[n].rgbRed = ent[n].peRed;
1400 col[n].rgbGreen = ent[n].peGreen;
1401 col[n].rgbBlue = ent[n].peBlue;
1402 col[n].rgbReserved = 0;
1405 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1407 for (n=0; n<256; n++) {
1408 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1409 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1410 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1411 col[n].rgbReserved = 0;
1415 SetDIBColorTable(This->hDC, 0, 256, col);
1419 TRACE("returning %p\n",*pHDC);
1420 This->Flags |= SFLAG_DCINUSE;
1425 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1426 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1428 TRACE("(%p)->(%p)\n",This,hDC);
1430 if (!(This->Flags & SFLAG_DCINUSE))
1431 return D3DERR_INVALIDCALL;
1433 /* we locked first, so unlock now */
1434 IWineD3DSurface_UnlockRect(iface);
1436 This->Flags &= ~SFLAG_DCINUSE;
1441 /* ******************************************************
1442 IWineD3DSurface Internal (No mapping to directx api) parts follow
1443 ****************************************************** */
1445 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1446 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1447 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1449 /* Default values: From the surface */
1450 *format = formatEntry->glFormat;
1451 *internal = formatEntry->glInternal;
1452 *type = formatEntry->glType;
1453 *convert = NO_CONVERSION;
1454 *target_bpp = This->bytesPerPixel;
1456 /* Ok, now look if we have to do any conversion */
1457 switch(This->resource.format) {
1462 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active) {
1464 *internal = GL_RGBA;
1465 *type = GL_UNSIGNED_BYTE;
1467 if(colorkey_active) {
1468 *convert = CONVERT_PALETTED_CK;
1470 *convert = CONVERT_PALETTED;
1476 case WINED3DFMT_R3G3B2:
1477 /* **********************
1478 GL_UNSIGNED_BYTE_3_3_2
1479 ********************** */
1480 if (colorkey_active) {
1481 /* This texture format will never be used.. So do not care about color keying
1482 up until the point in time it will be needed :-) */
1483 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1487 case WINED3DFMT_R5G6B5:
1488 if (colorkey_active) {
1489 *convert = CONVERT_CK_565;
1491 *internal = GL_RGBA;
1492 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1496 case WINED3DFMT_R8G8B8:
1497 if (colorkey_active) {
1498 *convert = CONVERT_CK_RGB24;
1500 *internal = GL_RGBA;
1501 *type = GL_UNSIGNED_INT_8_8_8_8;
1506 case WINED3DFMT_X8R8G8B8:
1507 if (colorkey_active) {
1508 *convert = CONVERT_RGB32_888;
1510 *internal = GL_RGBA;
1511 *type = GL_UNSIGNED_INT_8_8_8_8;
1515 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1516 case WINED3DFMT_A4R4G4B4:
1517 if (colorkey_active)
1519 *convert = CONVERT_CK_4444_ARGB;
1521 *internal = GL_RGBA;
1522 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1526 case WINED3DFMT_A1R5G5B5:
1527 if (colorkey_active)
1529 *convert = CONVERT_CK_1555;
1532 case WINED3DFMT_A8R8G8B8:
1533 if (colorkey_active)
1535 *convert = CONVERT_CK_8888_ARGB;
1537 *internal = GL_RGBA;
1538 *type = GL_UNSIGNED_INT_8_8_8_8;
1549 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1550 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1555 memcpy(dst, src, len * surf->bytesPerPixel);
1558 case CONVERT_PALETTED:
1559 case CONVERT_PALETTED_CK:
1561 IWineD3DPaletteImpl* pal = surf->palette;
1567 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1571 /* Still no palette? Use the device's palette */
1572 /* Get the surface's palette */
1573 for (i = 0; i < 256; i++) {
1574 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1576 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1577 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1578 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1579 if ((convert == CONVERT_PALETTED_CK) &&
1580 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1581 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1582 /* We should maybe here put a more 'neutral' color than the standard bright purple
1583 one often used by application to prevent the nice purple borders when bi-linear
1591 TRACE("Using surface palette %p\n", pal);
1592 /* Get the surface's palette */
1593 for (i = 0; i < 256; i++) {
1594 table[i][0] = pal->palents[i].peRed;
1595 table[i][1] = pal->palents[i].peGreen;
1596 table[i][2] = pal->palents[i].peBlue;
1597 if ((convert == CONVERT_PALETTED_CK) &&
1598 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1599 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1600 /* We should maybe here put a more 'neutral' color than the standard bright purple
1601 one often used by application to prevent the nice purple borders when bi-linear
1610 for (x = 0; x < len; x++) {
1611 BYTE color = *src++;
1612 *dst++ = table[color][0];
1613 *dst++ = table[color][1];
1614 *dst++ = table[color][2];
1615 *dst++ = table[color][3];
1620 case CONVERT_CK_565:
1622 /* Converting the 565 format in 5551 packed to emulate color-keying.
1624 Note : in all these conversion, it would be best to average the averaging
1625 pixels to get the color of the pixel that will be color-keyed to
1626 prevent 'color bleeding'. This will be done later on if ever it is
1629 Note2: when using color-keying + alpha, are the alpha bits part of the
1630 color-space or not ?
1633 WORD *Source = (WORD *) src;
1634 WORD *Dest = (WORD *) dst;
1636 TRACE("Color keyed 565\n");
1638 for (x = 0; x < len; x++ ) {
1639 WORD color = *Source++;
1640 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1641 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1642 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1650 case CONVERT_CK_1555:
1653 WORD *Source = (WORD *) src;
1654 WORD *Dest = (WORD *) dst;
1656 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1657 WORD color = *Source++;
1658 *Dest = (color & 0x7FFF);
1659 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1660 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1661 *Dest |= (color & 0x8000);
1667 case CONVERT_CK_4444_ARGB:
1669 /* Move the four Alpha bits... */
1671 WORD *Source = (WORD *) src;
1672 WORD *Dest = (WORD *) dst;
1674 for (x = 0; x < len; x++) {
1675 WORD color = *Source++;
1676 *dst = (color & 0x0FFF) << 4;
1677 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1678 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1679 *Dest |= (color & 0xF000) >> 12;
1685 ERR("Unsupported conversation type %d\n", convert);
1691 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1692 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1694 if (This->Flags & SFLAG_INTEXTURE) {
1695 TRACE("Surface already in texture\n");
1698 if (This->Flags & SFLAG_DIRTY) {
1699 TRACE("Reloading because surface is dirty\n");
1700 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1701 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1702 /* Reload: vice versa OR */
1703 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1704 /* Also reload: Color key is active AND the color key has changed */
1705 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1706 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1707 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1708 TRACE("Reloading because of color keying\n");
1710 TRACE("surface isn't dirty\n");
1714 This->Flags &= ~SFLAG_DIRTY;
1716 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1717 * These resources are not bound by device size or format restrictions. Because of this,
1718 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1719 * However, these resources can always be created, locked, and copied.
1721 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1723 FIXME("(%p) Operation not supported for scratch textures\n",This);
1724 return WINED3DERR_INVALIDCALL;
1727 if (This->Flags & SFLAG_INPBUFFER) {
1730 if (This->glDescription.level != 0)
1731 FIXME("Surface in texture is only supported for level 0\n");
1732 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1733 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1734 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1735 This->resource.format == WINED3DFMT_DXT5)
1736 FIXME("Format %d not supported\n", This->resource.format);
1739 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1740 vcheckGLcall("glGetIntegerv");
1741 glReadBuffer(GL_BACK);
1742 vcheckGLcall("glReadBuffer");
1744 glCopyTexImage2D(This->glDescription.target,
1745 This->glDescription.level,
1746 This->glDescription.glFormatInternal,
1749 This->currentDesc.Width,
1750 This->currentDesc.Height,
1753 checkGLcall("glCopyTexImage2D");
1754 glReadBuffer(prevRead);
1755 vcheckGLcall("glReadBuffer");
1756 TRACE("Updating target %d\n", This->glDescription.target);
1757 This->Flags |= SFLAG_INTEXTURE;
1763 /* TODO: Compressed non-power 2 support */
1765 if (This->resource.format == WINED3DFMT_DXT1 ||
1766 This->resource.format == WINED3DFMT_DXT2 ||
1767 This->resource.format == WINED3DFMT_DXT3 ||
1768 This->resource.format == WINED3DFMT_DXT4 ||
1769 This->resource.format == WINED3DFMT_DXT5) {
1770 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1771 FIXME("Using DXT1/3/5 without advertized support\n");
1772 } else if (This->resource.allocatedMemory) {
1773 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1774 This->glDescription.target,
1775 This->glDescription.level,
1776 This->glDescription.glFormatInternal,
1777 This->currentDesc.Width,
1778 This->currentDesc.Height,
1780 This->resource.size,
1781 This->resource.allocatedMemory);
1785 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1786 This->glDescription.level,
1787 This->glDescription.glFormatInternal,
1788 This->currentDesc.Width,
1789 This->currentDesc.Height,
1791 This->resource.size,
1792 This->resource.allocatedMemory);
1793 checkGLcall("glCommpressedTexImage2D");
1797 if(!(This->Flags & SFLAG_DONOTFREE)){
1798 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1799 This->resource.allocatedMemory = NULL;
1803 GLenum format, internal, type;
1804 CONVERT_TYPES convert;
1808 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1809 This->Flags |= SFLAG_GLCKEY;
1810 This->glCKey = This->SrcBltCKey;
1812 else This->Flags &= ~SFLAG_GLCKEY;
1813 d3dfmt_get_conv(This, TRUE /* We need color keying */, &format, &internal, &type, &convert, &bpp);
1815 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1816 int width = This->glRect.right - This->glRect.left;
1817 int height = This->glRect.bottom - This->glRect.top;
1818 int pitch = IWineD3DSurface_GetPitch(iface);
1820 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
1822 ERR("Out of memory %d, %d!\n", width, height);
1823 return WINED3DERR_OUTOFVIDEOMEMORY;
1826 d3dfmt_convert_surface(This->resource.allocatedMemory,
1831 /* Make sure the correct pitch is used */
1832 glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch);
1834 This->Flags |= SFLAG_CONVERTED;
1836 This->Flags &= ~SFLAG_CONVERTED;
1837 mem = This->resource.allocatedMemory;
1840 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1841 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE) ) {
1844 TRACE("non power of two support\n");
1846 TRACE("(%p) Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n", This,
1847 This->glDescription.target,
1848 This->glDescription.level,
1849 debug_d3dformat(This->resource.format),
1850 This->glDescription.glFormatInternal,
1854 This->glDescription.glFormat,
1855 This->glDescription.glType,
1858 glTexImage2D(This->glDescription.target,
1859 This->glDescription.level,
1860 This->glDescription.glFormatInternal,
1864 This->glDescription.glFormat,
1865 This->glDescription.glType,
1868 checkGLcall("glTexImage2D");
1869 if (This->resource.allocatedMemory != NULL) {
1870 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1871 /* And map the non-power two data into the top left corner */
1873 This->glDescription.target,
1874 This->glDescription.level,
1877 This->currentDesc.Width,
1878 This->currentDesc.Height,
1879 This->glDescription.glFormat,
1880 This->glDescription.glType,
1881 This->resource.allocatedMemory
1883 checkGLcall("glTexSubImage2D");
1889 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%ld, h=%ld,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1890 This->glDescription.target,
1891 This->glDescription.level,
1892 debug_d3dformat(This->resource.format),
1893 This->glDescription.glFormatInternal,
1894 This->glRect.right - This->glRect.left,
1895 This->glRect.bottom - This->glRect.top,
1897 This->glDescription.glFormat,
1898 This->glDescription.glType,
1903 /* OK, create the texture */
1904 glTexImage2D(This->glDescription.target,
1905 This->glDescription.level,
1907 This->glRect.right - This->glRect.left,
1908 This->glRect.bottom - This->glRect.top,
1914 checkGLcall("glTexImage2D");
1918 if(mem != This->resource.allocatedMemory)
1919 HeapFree(GetProcessHeap(), 0, mem);
1923 static unsigned int gen = 0;
1926 if ((gen % 10) == 0) {
1927 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1928 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1931 * debugging crash code
1939 if(!(This->Flags & SFLAG_DONOTFREE)){
1940 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1941 This->resource.allocatedMemory = NULL;
1951 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1954 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1955 char *allocatedMemory;
1957 IWineD3DSwapChain *swapChain = NULL;
1962 Textures my not be stored in ->allocatedgMemory and a GlTexture
1963 so we should lock the surface before saving a snapshot, or at least check that
1965 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1966 by calling GetTexImage and in compressed form by calling
1967 GetCompressedTexImageARB. Queried compressed images can be saved and
1968 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1969 texture images do not need to be processed by the GL and should
1970 significantly improve texture loading performance relative to uncompressed
1973 /* Setup the width and height to be the internal texture width and height. */
1974 width = This->pow2Width;
1975 height = This->pow2Height;
1976 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1977 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1979 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1980 /* 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 */
1983 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1984 glEnable(GL_TEXTURE_2D);
1986 glGenTextures(1, &tmpTexture);
1987 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1989 glTexImage2D(GL_TEXTURE_2D,
1996 GL_UNSIGNED_INT_8_8_8_8_REV,
1999 glGetIntegerv(GL_READ_BUFFER, &prevRead);
2000 vcheckGLcall("glGetIntegerv");
2001 glReadBuffer(GL_BACK);
2002 vcheckGLcall("glReadBuffer");
2003 glCopyTexImage2D(GL_TEXTURE_2D,
2012 checkGLcall("glCopyTexImage2D");
2013 glReadBuffer(prevRead);
2016 } else { /* bind the real texture */
2017 IWineD3DSurface_PreLoad(iface);
2019 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
2021 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
2022 glGetTexImage(GL_TEXTURE_2D,
2023 This->glDescription.level,
2025 GL_UNSIGNED_INT_8_8_8_8_REV,
2027 checkGLcall("glTexImage2D");
2029 glBindTexture(GL_TEXTURE_2D, 0);
2030 glDeleteTextures(1, &tmpTexture);
2034 f = fopen(filename, "w+");
2036 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2037 return WINED3DERR_INVALIDCALL;
2039 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
2040 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2055 fwrite(&width,2,1,f);
2057 fwrite(&height,2,1,f);
2062 /* 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*/
2064 textureRow = allocatedMemory + (width * (height - 1) *4);
2066 textureRow = allocatedMemory;
2067 for (y = 0 ; y < height; y++) {
2068 for (i = 0; i < width; i++) {
2069 color = *((DWORD*)textureRow);
2070 fputc((color >> 16) & 0xFF, f); /* B */
2071 fputc((color >> 8) & 0xFF, f); /* G */
2072 fputc((color >> 0) & 0xFF, f); /* R */
2073 fputc((color >> 24) & 0xFF, f); /* A */
2076 /* take two rows of the pointer to the texture memory */
2078 (textureRow-= width << 3);
2081 TRACE("Closing file\n");
2085 IWineD3DSwapChain_Release(swapChain);
2087 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2091 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2092 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2093 This->Flags &= ~SFLAG_DIRTY;
2094 This->dirtyRect.left = This->currentDesc.Width;
2095 This->dirtyRect.top = This->currentDesc.Height;
2096 This->dirtyRect.right = 0;
2097 This->dirtyRect.bottom = 0;
2098 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2099 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2104 * Slightly inefficient way to handle multiple dirty rects but it works :)
2106 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2107 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2108 IWineD3DBaseTexture *baseTexture = NULL;
2109 This->Flags |= SFLAG_DIRTY;
2110 if (NULL != pDirtyRect) {
2111 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2112 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2113 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2114 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2116 This->dirtyRect.left = 0;
2117 This->dirtyRect.top = 0;
2118 This->dirtyRect.right = This->currentDesc.Width;
2119 This->dirtyRect.bottom = This->currentDesc.Height;
2121 TRACE("(%p) : Dirty?%ld, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2122 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2123 /* if the container is a basetexture then mark it dirty. */
2124 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2125 TRACE("Passing to conatiner\n");
2126 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2127 IWineD3DBaseTexture_Release(baseTexture);
2132 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2133 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2135 TRACE("This %p, container %p\n", This, container);
2137 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2139 TRACE("Setting container to %p from %p\n", container, This->container);
2140 This->container = container;
2145 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2146 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2147 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2149 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2150 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2151 return WINED3DERR_INVALIDCALL;
2154 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2155 if (format == WINED3DFMT_UNKNOWN) {
2156 This->resource.size = 0;
2157 } else if (format == WINED3DFMT_DXT1) {
2158 /* DXT1 is half byte per pixel */
2159 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2161 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2162 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2163 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2165 This->resource.size = (This->pow2Width * formatEntry->bpp) * This->pow2Height;
2169 /* Setup some glformat defaults */
2170 This->glDescription.glFormat = formatEntry->glFormat;
2171 This->glDescription.glFormatInternal = formatEntry->glInternal;
2172 This->glDescription.glType = formatEntry->glType;
2174 if (format != WINED3DFMT_UNKNOWN) {
2175 This->bytesPerPixel = formatEntry->bpp;
2176 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2178 This->bytesPerPixel = 0;
2182 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2184 This->resource.format = format;
2186 TRACE("(%p) : Size %d, pow2Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->pow2Size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
2191 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2192 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2194 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2195 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2196 ERR("Not supported on render targets\n");
2197 return WINED3DERR_INVALIDCALL;
2200 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2201 WARN("Surface is locked or the HDC is in use\n");
2202 return WINED3DERR_INVALIDCALL;
2205 if(Mem && Mem != This->resource.allocatedMemory) {
2207 /* Do I have to copy the old surface content? */
2208 if(This->Flags & SFLAG_DIBSECTION) {
2209 /* Release the DC. No need to hold the critical section for the update
2210 * Thread because this thread runs only on front buffers, but this method
2211 * fails for render targets in the check above.
2213 SelectObject(This->hDC, This->dib.holdbitmap);
2214 DeleteDC(This->hDC);
2215 /* Release the DIB section */
2216 DeleteObject(This->dib.DIBsection);
2217 This->dib.bitmap_data = NULL;
2218 This->resource.allocatedMemory = NULL;
2220 This->Flags &= ~SFLAG_DIBSECTION;
2221 } else if(!(This->Flags & SFLAG_USERPTR)) {
2222 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2224 This->resource.allocatedMemory = Mem;
2225 This->Flags |= SFLAG_USERPTR;
2226 } else if(This->Flags & SFLAG_USERPTR) {
2227 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2228 This->resource.allocatedMemory = NULL;
2229 This->Flags &= ~SFLAG_USERPTR;
2234 /* TODO: replace this function with context management routines */
2235 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2236 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2239 This->Flags |= SFLAG_INPBUFFER;
2241 This->Flags &= ~SFLAG_INPBUFFER;
2245 This->Flags |= SFLAG_INTEXTURE;
2247 This->Flags &= ~SFLAG_INTEXTURE;
2253 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2254 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2255 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2256 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
2258 /* Flipping is only supported on RenderTargets */
2259 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2262 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2263 * FIXME("(%p) Target override is not supported by now\n", This);
2264 * Additionally, it isn't really possible to support triple-buffering
2265 * properly on opengl at all
2269 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2270 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2273 /* Not called from the VTable */
2274 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2276 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2277 IWineD3DSwapChainImpl *swapchain = NULL;
2278 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2281 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2283 /* Get the swapchain. One of the surfaces has to be a primary surface */
2284 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2285 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2287 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2288 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2289 else return WINED3DERR_INVALIDCALL;
2295 rect.x1 = DestRect->left;
2296 rect.y1 = DestRect->top;
2297 rect.x2 = DestRect->right;
2298 rect.y2 = DestRect->bottom;
2302 rect.x2 = This->currentDesc.Width;
2303 rect.y2 = This->currentDesc.Height;
2306 /* Half-life does a Blt from the back buffer to the front buffer,
2307 * Full surface size, no flags... Use present instead
2311 /* First, check if we can do a Flip */
2313 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2315 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2316 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2323 /* Check the Destination rect and the surface sizes */
2325 (rect.x1 == 0) && (rect.y1 == 0) &&
2326 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2327 (This->currentDesc.Width == Src->currentDesc.Width) &&
2328 (This->currentDesc.Height == Src->currentDesc.Height)) {
2329 /* These flags are unimportant for the flag check, remove them */
2331 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2332 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2334 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2336 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2337 * take very long, while a flip is fast.
2338 * This applies to Half-Life, which does such Blts every time it finished
2339 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2340 * menu. This is also used by all apps when they do windowed rendering
2342 * The problem is that flipping is not really the same as copying. After a
2343 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2344 * untouched. Therefore it's necessary to override the swap effect
2345 * and to set it back after the flip.
2348 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2350 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2351 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2352 NULL, NULL, 0, NULL);
2354 swapchain->presentParms.SwapEffect = orig_swap;
2361 /* Blt from texture to rendertarget? */
2362 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2363 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2365 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2366 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2367 float glTexCoord[4];
2369 DDCOLORKEY oldBltCKey = {0,0};
2370 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2374 RECT SourceRectangle;
2377 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2380 SourceRectangle.left = SrcRect->left;
2381 SourceRectangle.right = SrcRect->right;
2382 SourceRectangle.top = SrcRect->top;
2383 SourceRectangle.bottom = SrcRect->bottom;
2385 SourceRectangle.left = 0;
2386 SourceRectangle.right = Src->currentDesc.Width;
2387 SourceRectangle.top = 0;
2388 SourceRectangle.bottom = Src->currentDesc.Height;
2391 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2392 /* Fall back to software */
2393 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2394 SourceRectangle.left, SourceRectangle.top,
2395 SourceRectangle.right, SourceRectangle.bottom);
2396 return WINED3DERR_INVALIDCALL;
2399 /* Color keying: Check if we have to do a color keyed blt,
2400 * and if not check if a color key is activated.
2402 oldCKey = Src->CKeyFlags;
2403 if(!(Flags & DDBLT_KEYSRC) &&
2404 Src->CKeyFlags & DDSD_CKSRCBLT) {
2405 /* Ok, the surface has a color key, but we shall not use it -
2406 * Deactivate it for now, LoadTexture will catch this
2408 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2412 if(Flags & DDBLT_KEYDEST) {
2413 oldBltCKey = This->SrcBltCKey;
2414 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2415 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2417 This->SrcBltCKey = This->DestBltCKey;
2418 } else if (Flags & DDBLT_KEYSRC)
2419 oldBltCKey = This->SrcBltCKey;
2421 /* Now load the surface */
2422 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2426 /* Save all the old stuff until we have a proper opengl state manager */
2427 oldLight = glIsEnabled(GL_LIGHTING);
2428 oldFog = glIsEnabled(GL_FOG);
2429 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2430 oldBlend = glIsEnabled(GL_BLEND);
2431 oldCull = glIsEnabled(GL_CULL_FACE);
2432 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2433 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2435 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2436 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2437 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2438 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2440 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2441 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2442 TRACE("Drawing to front buffer\n");
2443 glDrawBuffer(GL_FRONT);
2444 checkGLcall("glDrawBuffer GL_FRONT");
2447 /* Unbind the old texture */
2448 glBindTexture(GL_TEXTURE_2D, 0);
2450 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2451 /* We use texture unit 0 for blts */
2452 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2453 checkGLcall("glActiveTextureARB");
2455 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2458 /* Disable some fancy graphics effects */
2459 glDisable(GL_LIGHTING);
2460 checkGLcall("glDisable GL_LIGHTING");
2461 glDisable(GL_DEPTH_TEST);
2462 checkGLcall("glDisable GL_DEPTH_TEST");
2464 checkGLcall("glDisable GL_FOG");
2465 glDisable(GL_BLEND);
2466 checkGLcall("glDisable GL_BLEND");
2467 glDisable(GL_CULL_FACE);
2468 checkGLcall("glDisable GL_CULL_FACE");
2469 glDisable(GL_STENCIL_TEST);
2470 checkGLcall("glDisable GL_STENCIL_TEST");
2472 /* Ok, we need 2d textures, but not 1D or 3D */
2473 glDisable(GL_TEXTURE_1D);
2474 checkGLcall("glDisable GL_TEXTURE_1D");
2475 glEnable(GL_TEXTURE_2D);
2476 checkGLcall("glEnable GL_TEXTURE_2D");
2477 glDisable(GL_TEXTURE_3D);
2478 checkGLcall("glDisable GL_TEXTURE_3D");
2480 /* Bind the texture */
2481 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2482 checkGLcall("glBindTexture");
2484 glEnable(GL_SCISSOR_TEST);
2486 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2488 /* No filtering for blts */
2489 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2491 checkGLcall("glTexParameteri");
2492 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2494 checkGLcall("glTexParameteri");
2495 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2496 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2497 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2498 checkGLcall("glTexEnvi");
2500 /* This is for color keying */
2501 if(Flags & DDBLT_KEYSRC) {
2502 glEnable(GL_ALPHA_TEST);
2503 checkGLcall("glEnable GL_ALPHA_TEST");
2504 glAlphaFunc(GL_NOTEQUAL, 0.0);
2505 checkGLcall("glAlphaFunc\n");
2507 glDisable(GL_ALPHA_TEST);
2508 checkGLcall("glDisable GL_ALPHA_TEST");
2511 /* Draw a textured quad
2513 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2517 glColor3d(1.0f, 1.0f, 1.0f);
2518 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2523 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2524 glVertex3f(rect.x1, rect.y2, 0.0);
2526 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2531 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2536 checkGLcall("glEnd");
2538 /* Unbind the texture */
2539 glBindTexture(GL_TEXTURE_2D, 0);
2540 checkGLcall("glEnable glBindTexture");
2542 /* Restore the old settings */
2544 glEnable(GL_LIGHTING);
2545 checkGLcall("glEnable GL_LIGHTING");
2549 checkGLcall("glEnable GL_FOG");
2552 glEnable(GL_DEPTH_TEST);
2553 checkGLcall("glEnable GL_DEPTH_TEST");
2557 checkGLcall("glEnable GL_BLEND");
2560 glEnable(GL_CULL_FACE);
2561 checkGLcall("glEnable GL_CULL_FACE");
2564 glEnable(GL_STENCIL_TEST);
2565 checkGLcall("glEnable GL_STENCIL_TEST");
2568 glDisable(GL_ALPHA_TEST);
2569 checkGLcall("glDisable GL_ALPHA_TEST");
2571 glEnable(GL_ALPHA_TEST);
2572 checkGLcall("glEnable GL_ALPHA_TEST");
2575 glAlphaFunc(alphafunc, alpharef);
2576 checkGLcall("glAlphaFunc\n");
2578 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2579 glDrawBuffer(oldDraw);
2582 /* Restore the color key flags */
2583 if(oldCKey != Src->CKeyFlags) {
2584 Src->CKeyFlags = oldCKey;
2587 /* Restore the old color key */
2588 if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
2589 This->SrcBltCKey = oldBltCKey;
2593 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2594 This->Flags |= SFLAG_GLDIRTY;
2600 /* Blt from rendertarget to texture? */
2601 if( (SrcSurface == swapchain->frontBuffer) ||
2602 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2603 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2604 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2609 TRACE("Blt from rendertarget to texture\n");
2611 /* Call preload for the surface to make sure it isn't dirty */
2612 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2615 srect.x1 = SrcRect->left;
2616 srect.y1 = SrcRect->top;
2617 srect.x2 = SrcRect->right;
2618 srect.y2 = SrcRect->bottom;
2622 srect.x2 = Src->currentDesc.Width;
2623 srect.y2 = Src->currentDesc.Height;
2628 /* Bind the target texture */
2629 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2630 checkGLcall("glBindTexture");
2631 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2632 glReadBuffer(GL_BACK);
2634 glReadBuffer(GL_FRONT);
2636 checkGLcall("glReadBuffer");
2638 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2639 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2641 /* I have to process this row by row to swap the image,
2642 * otherwise it would be upside down, so streching in y direction
2643 * doesn't cost extra time
2645 * However, streching in x direction can be avoided if not necessary
2647 for(row = rect.y1; row < rect.y2; row++) {
2648 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2649 /* Well, that stuff works, but it's very slow.
2650 * find a better way instead
2653 for(col = rect.x1; col < rect.x2; col++) {
2654 glCopyTexSubImage2D(GL_TEXTURE_2D,
2656 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2657 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2661 glCopyTexSubImage2D(GL_TEXTURE_2D,
2663 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2664 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2669 vcheckGLcall("glCopyTexSubImage2D");
2672 if(!(This->Flags & SFLAG_DONOTFREE)) {
2673 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2674 This->resource.allocatedMemory = NULL;
2676 This->Flags |= SFLAG_GLDIRTY;
2684 if (Flags & DDBLT_COLORFILL) {
2685 /* This is easy to handle for the D3D Device... */
2687 IWineD3DSwapChainImpl *implSwapChain;
2689 TRACE("Colorfill\n");
2691 /* The color as given in the Blt function is in the format of the frame-buffer...
2692 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2694 if (This->resource.format == WINED3DFMT_P8) {
2695 if (This->palette) {
2696 color = ((0xFF000000) |
2697 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2698 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2699 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2704 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2705 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2708 color = ((0xFF000000) |
2709 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2710 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2711 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2714 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2715 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2716 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2718 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2719 color = DDBltFx->u5.dwFillColor;
2722 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2723 return WINED3DERR_INVALIDCALL;
2726 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2727 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2728 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2729 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2730 glDrawBuffer(GL_BACK);
2731 checkGLcall("glDrawBuffer(GL_BACK)");
2733 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2734 glDrawBuffer(GL_FRONT);
2735 checkGLcall("glDrawBuffer(GL_FRONT)");
2738 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2739 return WINED3DERR_INVALIDCALL;
2742 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2744 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2745 1 /* Number of rectangles */,
2752 /* Restore the original draw buffer */
2753 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2754 glDrawBuffer(GL_BACK);
2755 vcheckGLcall("glDrawBuffer");
2761 /* Default: Fall back to the generic blt */
2762 return WINED3DERR_INVALIDCALL;
2765 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2766 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2767 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2768 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2769 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2771 /* Special cases for RenderTargets */
2772 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2773 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2774 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2777 /* For the rest call the X11 surface implementation.
2778 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2779 * other Blts are rather rare
2781 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2784 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2785 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2786 TRACE("(%p)->(%lx)\n", This, Flags);
2791 case DDGBS_ISBLTDONE:
2795 return DDERR_INVALIDPARAMS;
2799 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2800 /* XXX: DDERR_INVALIDSURFACETYPE */
2802 TRACE("(%p)->(%08lx)\n",iface,Flags);
2805 case DDGFS_ISFLIPDONE:
2809 return DDERR_INVALIDPARAMS;
2813 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2814 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2815 TRACE("(%p)\n", This);
2817 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2820 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2821 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2822 TRACE("(%p)\n", This);
2824 /* So far we don't lose anything :) */
2825 This->Flags &= ~SFLAG_LOST;
2829 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2830 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2831 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2832 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2834 /* Special cases for RenderTargets */
2835 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2836 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2838 RECT SrcRect, DstRect;
2842 SrcRect.left = rsrc->left;
2843 SrcRect.top= rsrc->top;
2844 SrcRect.bottom = rsrc->bottom;
2845 SrcRect.right = rsrc->right;
2849 SrcRect.right = srcImpl->currentDesc.Width;
2850 SrcRect.bottom = srcImpl->currentDesc.Height;
2853 DstRect.left = dstx;
2855 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2856 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2858 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt aswell */
2859 if(trans & DDBLTFAST_SRCCOLORKEY)
2860 Flags |= DDBLT_KEYSRC;
2861 if(trans & DDBLTFAST_DESTCOLORKEY)
2862 Flags |= DDBLT_KEYDEST;
2863 if(trans & DDBLTFAST_WAIT)
2864 Flags |= DDBLT_WAIT;
2865 if(trans & DDBLTFAST_DONOTWAIT)
2866 Flags |= DDBLT_DONOTWAIT;
2868 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2872 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2875 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2876 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2877 TRACE("(%p)->(%p)\n", This, Pal);
2879 *Pal = (IWineD3DPalette *) This->palette;
2883 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2884 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2886 IWineD3DPaletteImpl *pal = This->palette;
2888 TRACE("(%p)\n", This);
2890 if(This->resource.format == WINED3DFMT_P8 ||
2891 This->resource.format == WINED3DFMT_A8P8)
2893 TRACE("Dirtifying surface\n");
2894 This->Flags |= SFLAG_DIRTY;
2897 if(This->Flags & SFLAG_DIBSECTION) {
2898 TRACE("(%p): Updating the hdc's palette\n", This);
2899 for (n=0; n<256; n++) {
2901 col[n].rgbRed = pal->palents[n].peRed;
2902 col[n].rgbGreen = pal->palents[n].peGreen;
2903 col[n].rgbBlue = pal->palents[n].peBlue;
2905 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2906 /* Use the default device palette */
2907 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2908 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2909 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2911 col[n].rgbReserved = 0;
2913 SetDIBColorTable(This->hDC, 0, 256, col);
2919 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2920 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2921 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2922 TRACE("(%p)->(%p)\n", This, Pal);
2924 if(This->palette != NULL)
2925 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2926 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2928 if(PalImpl != NULL) {
2929 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2930 /* Set the device's main palette if the palette
2931 * wasn't a primary palette before
2933 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2934 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2937 for(i=0; i < 256; i++) {
2938 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2942 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2945 This->palette = PalImpl;
2947 return IWineD3DSurface_RealizePalette(iface);
2950 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2951 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2952 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
2954 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2955 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
2956 return DDERR_INVALIDPARAMS;
2959 /* Dirtify the surface, but only if a key was changed */
2961 switch (Flags & ~DDCKEY_COLORSPACE) {
2962 case DDCKEY_DESTBLT:
2963 This->DestBltCKey = *CKey;
2964 This->CKeyFlags |= DDSD_CKDESTBLT;
2967 case DDCKEY_DESTOVERLAY:
2968 This->DestOverlayCKey = *CKey;
2969 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2972 case DDCKEY_SRCOVERLAY:
2973 This->SrcOverlayCKey = *CKey;
2974 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2978 This->SrcBltCKey = *CKey;
2979 This->CKeyFlags |= DDSD_CKSRCBLT;
2984 switch (Flags & ~DDCKEY_COLORSPACE) {
2985 case DDCKEY_DESTBLT:
2986 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2989 case DDCKEY_DESTOVERLAY:
2990 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2993 case DDCKEY_SRCOVERLAY:
2994 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2998 This->CKeyFlags &= ~DDSD_CKSRCBLT;
3006 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3007 /** Check against the maximum texture sizes supported by the video card **/
3008 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3010 TRACE("%p\n", This);
3011 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3012 /* one of three options
3013 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)
3014 2: Set the texture to the maxium size (bad idea)
3015 3: WARN and return WINED3DERR_NOTAVAILABLE;
3016 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.
3018 WARN("(%p) Creating an oversized surface\n", This);
3019 This->Flags |= SFLAG_OVERSIZE;
3021 /* This will be initialized on the first blt */
3022 This->glRect.left = 0;
3023 This->glRect.top = 0;
3024 This->glRect.right = 0;
3025 This->glRect.bottom = 0;
3027 /* No oversize, gl rect is the full texture size */
3028 This->Flags &= ~SFLAG_OVERSIZE;
3029 This->glRect.left = 0;
3030 This->glRect.top = 0;
3031 This->glRect.right = This->pow2Width;
3032 This->glRect.bottom = This->pow2Height;
3038 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3039 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3041 TRACE("(%p)\n", This);
3043 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3044 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3045 ie pitch = (width/4) * bytes per block */
3046 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3047 ret = (This->currentDesc.Width >> 2) << 3;
3048 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3049 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3050 ret = (This->currentDesc.Width >> 2) << 4;
3052 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3053 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3054 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3056 ret = This->bytesPerPixel * This->pow2Width;
3059 TRACE("(%p) Returning %ld\n", This, ret);
3063 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3066 IWineD3DSurfaceImpl_QueryInterface,
3067 IWineD3DSurfaceImpl_AddRef,
3068 IWineD3DSurfaceImpl_Release,
3069 /* IWineD3DResource */
3070 IWineD3DSurfaceImpl_GetParent,
3071 IWineD3DSurfaceImpl_GetDevice,
3072 IWineD3DSurfaceImpl_SetPrivateData,
3073 IWineD3DSurfaceImpl_GetPrivateData,
3074 IWineD3DSurfaceImpl_FreePrivateData,
3075 IWineD3DSurfaceImpl_SetPriority,
3076 IWineD3DSurfaceImpl_GetPriority,
3077 IWineD3DSurfaceImpl_PreLoad,
3078 IWineD3DSurfaceImpl_GetType,
3079 /* IWineD3DSurface */
3080 IWineD3DSurfaceImpl_GetContainerParent,
3081 IWineD3DSurfaceImpl_GetContainer,
3082 IWineD3DSurfaceImpl_GetDesc,
3083 IWineD3DSurfaceImpl_LockRect,
3084 IWineD3DSurfaceImpl_UnlockRect,
3085 IWineD3DSurfaceImpl_GetDC,
3086 IWineD3DSurfaceImpl_ReleaseDC,
3087 IWineD3DSurfaceImpl_Flip,
3088 IWineD3DSurfaceImpl_Blt,
3089 IWineD3DSurfaceImpl_GetBltStatus,
3090 IWineD3DSurfaceImpl_GetFlipStatus,
3091 IWineD3DSurfaceImpl_IsLost,
3092 IWineD3DSurfaceImpl_Restore,
3093 IWineD3DSurfaceImpl_BltFast,
3094 IWineD3DSurfaceImpl_GetPalette,
3095 IWineD3DSurfaceImpl_SetPalette,
3096 IWineD3DSurfaceImpl_RealizePalette,
3097 IWineD3DSurfaceImpl_SetColorKey,
3098 IWineD3DSurfaceImpl_GetPitch,
3099 IWineD3DSurfaceImpl_SetMem,
3101 IWineD3DSurfaceImpl_CleanDirtyRect,
3102 IWineD3DSurfaceImpl_AddDirtyRect,
3103 IWineD3DSurfaceImpl_LoadTexture,
3104 IWineD3DSurfaceImpl_SaveSnapshot,
3105 IWineD3DSurfaceImpl_SetContainer,
3106 IWineD3DSurfaceImpl_SetPBufferState,
3107 IWineD3DSurfaceImpl_SetGlTextureDesc,
3108 IWineD3DSurfaceImpl_GetGlDesc,
3109 IWineD3DSurfaceImpl_GetData,
3110 IWineD3DSurfaceImpl_SetFormat,
3111 IWineD3DSurfaceImpl_PrivateSetup