wined3d: Draw the cursor.
[wine/testsucceed.git] / dlls / wined3d / surface.c
blob9c2ed607eaf81182e55462bbad8bc0fca142e652
1 /*
2 * IWineD3DSurface Implementation
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006 Stefan Dösinger for CodeWeavers
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "config.h"
28 #include "wine/port.h"
29 #include "wined3d_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
32 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
34 typedef enum {
35 NO_CONVERSION,
36 CONVERT_PALETTED,
37 CONVERT_PALETTED_CK,
38 CONVERT_CK_565,
39 CONVERT_CK_5551,
40 CONVERT_CK_4444,
41 CONVERT_CK_4444_ARGB,
42 CONVERT_CK_1555,
43 CONVERT_555,
44 CONVERT_CK_RGB24,
45 CONVERT_CK_8888,
46 CONVERT_CK_8888_ARGB,
47 CONVERT_RGB32_888
48 } CONVERT_TYPES;
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);
60 if (riid == NULL) {
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);
68 *ppobj = This;
69 return S_OK;
71 *ppobj = NULL;
72 return E_NOINTERFACE;
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);
79 return ref;
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);
86 if (ref == 0) {
87 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
88 TRACE("(%p) : cleaning up\n", This);
89 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
90 ENTER_GL();
91 TRACE("Deleting texture %d\n", This->glDescription.textureName);
92 glDeleteTextures(1, &This->glDescription.textureName);
93 LEAVE_GL();
96 if(This->Flags & SFLAG_DIBSECTION) {
97 /* Release the DC */
98 SelectObject(This->hDC, This->dib.holdbitmap);
99 DeleteDC(This->hDC);
100 /* Release the DIB section */
101 DeleteObject(This->dib.DIBsection);
102 This->dib.bitmap_data = NULL;
103 This->resource.allocatedMemory = NULL;
106 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
107 if(iface == device->ddraw_primary)
108 device->ddraw_primary = NULL;
110 TRACE("(%p) Released\n", This);
111 HeapFree(GetProcessHeap(), 0, This);
114 return ref;
117 /* ****************************************************
118 IWineD3DSurface IWineD3DResource parts follow
119 **************************************************** */
120 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
121 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
124 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
125 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
128 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
129 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
132 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
133 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
136 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
137 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
140 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
141 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
144 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
145 /* TODO: re-write the way textures and managed,
146 * use a 'opengl context manager' to manage RenderTarget surfaces
147 ** *********************************************************/
149 /* TODO: check for locks */
150 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
151 IWineD3DBaseTexture *baseTexture = NULL;
152 TRACE("(%p)Checking to see if the container is a base texture\n", This);
153 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
154 TRACE("Passing to conatiner\n");
155 IWineD3DBaseTexture_PreLoad(baseTexture);
156 IWineD3DBaseTexture_Release(baseTexture);
157 } else {
158 TRACE("(%p) : About to load surface\n", This);
159 ENTER_GL();
160 #if 0 /* TODO: context manager support */
161 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
162 #endif
163 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
164 if (This->glDescription.level == 0 && This->glDescription.textureName == 0) {
165 glGenTextures(1, &This->glDescription.textureName);
166 checkGLcall("glGenTextures");
167 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
168 glBindTexture(This->glDescription.target, This->glDescription.textureName);
169 checkGLcall("glBindTexture");
170 IWineD3DSurface_LoadTexture(iface);
171 /* This is where we should be reducing the amount of GLMemoryUsed */
172 } else {
173 if (This->glDescription.level == 0) {
174 glBindTexture(This->glDescription.target, This->glDescription.textureName);
175 checkGLcall("glBindTexture");
176 IWineD3DSurface_LoadTexture(iface);
177 } else if (This->glDescription.textureName != 0) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
178 /* assume this is a coding error not a real error for now */
179 FIXME("Mipmap surface has a glTexture bound to it!\n");
182 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
183 /* Tell opengl to try and keep this texture in video ram (well mostly) */
184 GLclampf tmp;
185 tmp = 0.9f;
186 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
188 /* TODO: disable texture support, if it wastn't enabled when we entered. */
189 #if 0 /* TODO: context manager support */
190 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
191 /* we don't care when the state is disabled(if atall) */);
192 #endif
193 LEAVE_GL();
195 return;
198 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
199 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
200 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
203 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
204 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
205 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
208 /* ******************************************************
209 IWineD3DSurface IWineD3DSurface parts follow
210 ****************************************************** */
212 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainerParent(IWineD3DSurface* iface, IUnknown **ppContainerParent) {
213 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
215 TRACE("(%p) : ppContainerParent %p)\n", This, ppContainerParent);
217 if (!ppContainerParent) {
218 ERR("(%p) : Called without a valid ppContainerParent.\n", This);
221 if (This->container) {
222 IWineD3DBase_GetParent(This->container, ppContainerParent);
223 if (!ppContainerParent) {
224 /* WineD3D objects should always have a parent */
225 ERR("(%p) : GetParent returned NULL\n", This);
227 IUnknown_Release(*ppContainerParent); /* GetParent adds a reference; we want just the pointer */
228 } else {
229 *ppContainerParent = NULL;
232 return WINED3D_OK;
235 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
236 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
237 IWineD3DBase *container = 0;
239 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
241 if (!ppContainer) {
242 ERR("Called without a valid ppContainer.\n");
245 /** From MSDN:
246 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
247 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
248 * GetContainer will return the Direct3D device used to create the surface.
250 if (This->container) {
251 container = This->container;
252 } else {
253 container = (IWineD3DBase *)This->resource.wineD3DDevice;
256 TRACE("Relaying to QueryInterface\n");
257 return IUnknown_QueryInterface(container, riid, ppContainer);
260 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
261 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
263 TRACE("(%p) : copying into %p\n", This, pDesc);
264 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
265 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
266 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
267 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
268 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
269 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
270 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
271 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
272 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
273 return WINED3D_OK;
276 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
277 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
278 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
279 if (This->glDescription.textureName == 0 && textureName != 0) {
280 This->Flags |= SFLAG_DIRTY;
281 IWineD3DSurface_AddDirtyRect(iface, NULL);
283 This->glDescription.textureName = textureName;
284 This->glDescription.target = target;
287 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
288 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
289 TRACE("(%p) : returning %p\n", This, &This->glDescription);
290 *glDescription = &This->glDescription;
293 /* TODO: think about moving this down to resource? */
294 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
295 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
296 /* 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 */
297 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
298 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
300 return (CONST void*)(This->resource.allocatedMemory);
303 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
304 long j;
305 void *mem;
306 GLint fmt;
307 GLint type;
309 switch(This->resource.format)
311 case WINED3DFMT_P8:
313 /* GL can't return palettized data, so read ARGB pixels into a
314 * seperate block of memory and convert them into palettized format
315 * in software. Slow, but if the app means to use palettized render
316 * targets and lock it...
318 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
319 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
320 * for the color channels when palettizing the colors.
322 fmt = GL_RGB;
323 type = GL_UNSIGNED_BYTE;
324 pitch *= 3;
325 mem = HeapAlloc(GetProcessHeap(), 0, (rect->bottom - rect->top) * pitch);
326 if(!mem) {
327 ERR("Out of memory\n");
328 return;
331 break;
333 default:
334 mem = dest;
335 fmt = This->glDescription.glFormat;
336 type = This->glDescription.glType;
339 if (rect->left == 0 &&
340 rect->right == This->currentDesc.Width ) {
341 BYTE *row, *top, *bottom;
342 int i;
344 glReadPixels(0, rect->top,
345 This->currentDesc.Width,
346 rect->bottom - rect->top,
347 fmt,
348 type,
349 mem);
351 /* glReadPixels returns the image upside down, and there is no way to prevent this.
352 Flip the lines in software */
353 row = HeapAlloc(GetProcessHeap(), 0, pitch);
354 if(!row) {
355 ERR("Out of memory\n");
356 return;
358 top = mem;
359 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
360 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
361 memcpy(row, top, pitch);
362 memcpy(top, bottom, pitch);
363 memcpy(bottom, row, pitch);
364 top += pitch;
365 bottom -= pitch;
367 HeapFree(GetProcessHeap(), 0, row);
369 if(This->lockedRect.top == 0 && This->lockedRect.bottom == This->currentDesc.Height) {
370 This->Flags &= ~SFLAG_GLDIRTY;
372 } else {
373 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
374 glReadPixels(rect->left,
375 rect->bottom - j - 1,
376 rect->right - rect->left,
378 fmt,
379 type,
380 (char *)mem + (pitch * (j-rect->top)));
384 vcheckGLcall("glReadPixels");
386 if(This->resource.format == WINED3DFMT_P8) {
387 PALETTEENTRY *pal;
388 DWORD width = pitch / 3;
389 int x, y, c;
390 if(This->palette) {
391 pal = This->palette->palents;
392 } else {
393 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
396 for(y = rect->top; y < rect->bottom; y++) {
397 for(x = rect->left; x < rect->right; x++) {
398 /* start lines pixels */
399 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
400 BYTE *green = blue + 1;
401 BYTE *red = green + 1;
403 for(c = 0; c < 256; c++) {
404 if(*red == pal[c].peRed &&
405 *green == pal[c].peGreen &&
406 *blue == pal[c].peBlue)
408 *((BYTE *) dest + y * width + x) = c;
409 break;
414 HeapFree(GetProcessHeap(), 0, mem);
418 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
419 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
420 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
421 IWineD3DSwapChainImpl *swapchain = NULL;
422 static UINT messages = 0; /* holds flags to disable fixme messages */
423 BOOL backbuf = FALSE;
425 /* fixme: should we really lock as such? */
426 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
427 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
428 FIXME("Warning: Surface is in texture memory or pbuffer\n");
429 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
432 if (!(This->Flags & SFLAG_LOCKABLE)) {
433 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
434 texture regions, and since the destination is an unlockable region we need
435 to tolerate this */
436 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
437 /*return WINED3DERR_INVALIDCALL; */
440 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
441 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
443 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
444 if(swapchain != NULL) {
445 int i;
446 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
447 if(iface == swapchain->backBuffer[i]) {
448 backbuf = TRUE;
449 break;
453 if (backbuf) {
454 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
455 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
456 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
457 } else if (iface == myDevice->renderTarget) {
458 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
459 } else if (iface == myDevice->depthStencilBuffer) {
460 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
463 if (NULL != swapchain) {
464 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
466 swapchain = NULL;
468 } else {
469 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
472 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
474 if (NULL == pRect) {
475 pLockedRect->pBits = This->resource.allocatedMemory;
476 This->lockedRect.left = 0;
477 This->lockedRect.top = 0;
478 This->lockedRect.right = This->currentDesc.Width;
479 This->lockedRect.bottom = This->currentDesc.Height;
480 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);
481 } else {
482 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
484 if ((pRect->top < 0) ||
485 (pRect->left < 0) ||
486 (pRect->left >= pRect->right) ||
487 (pRect->top >= pRect->bottom) ||
488 (pRect->right > This->currentDesc.Width) ||
489 (pRect->bottom > This->currentDesc.Height))
491 WARN(" Invalid values in pRect !!!\n");
492 return D3DERR_INVALIDCALL;
495 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
496 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
497 } else {
498 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
500 This->lockedRect.left = pRect->left;
501 This->lockedRect.top = pRect->top;
502 This->lockedRect.right = pRect->right;
503 This->lockedRect.bottom = pRect->bottom;
506 if (This->Flags & SFLAG_NONPOW2) {
507 TRACE("Locking non-power 2 texture\n");
510 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
511 /* classic surface TODO: non 2d surfaces?
512 These resources may be POOL_SYSTEMMEM, so they must not access the device */
513 TRACE("locking an ordinarary surface\n");
514 /* Check to see if memory has already been allocated from the surface*/
515 if ((NULL == This->resource.allocatedMemory) ||
516 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
517 /* Non-system memory surfaces */
519 This->Flags &= ~SFLAG_GLDIRTY;
521 /*Surface has no memory currently allocated to it!*/
522 TRACE("(%p) Locking rect\n" , This);
523 if(!This->resource.allocatedMemory) {
524 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
526 if (0 != This->glDescription.textureName) {
527 /* Now I have to copy thing bits back */
528 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
529 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
530 ENTER_GL();
532 /* Make sure that the texture is loaded */
533 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
535 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);
537 if (This->resource.format == WINED3DFMT_DXT1 ||
538 This->resource.format == WINED3DFMT_DXT2 ||
539 This->resource.format == WINED3DFMT_DXT3 ||
540 This->resource.format == WINED3DFMT_DXT4 ||
541 This->resource.format == WINED3DFMT_DXT5) {
542 TRACE("Locking a compressed texture\n");
543 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* we can assume this as the texture would not have been created otherwise */
544 GL_EXTCALL(glGetCompressedTexImageARB)(This->glDescription.target,
545 This->glDescription.level,
546 This->resource.allocatedMemory);
548 } else {
549 FIXME("(%p) attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
551 } else {
552 glGetTexImage(This->glDescription.target,
553 This->glDescription.level,
554 This->glDescription.glFormat,
555 This->glDescription.glType,
556 This->resource.allocatedMemory);
557 vcheckGLcall("glGetTexImage");
558 if (NP2_REPACK == wined3d_settings.nonpower2_mode) {
559 /* some games (e.g. warhammer 40k) don't work with the odd pitchs properly, preventing
560 the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
561 repack the texture so that the bpp * width pitch can be used instead of the bpp * pow2width.
563 Were doing this...
565 instead of boxing the texture :
566 |<-texture width ->| -->pow2width| /\
567 |111111111111111111| | |
568 |222 Texture 222222| boxed empty | texture height
569 |3333 Data 33333333| | |
570 |444444444444444444| | \/
571 ----------------------------------- |
572 | boxed empty | boxed empty | pow2height
573 | | | \/
574 -----------------------------------
577 were repacking the data to the expected texture width
579 |<-texture width ->| -->pow2width| /\
580 |111111111111111111222222222222222| |
581 |222333333333333333333444444444444| texture height
582 |444444 | |
583 | | \/
584 | | |
585 | empty | pow2height
586 | | \/
587 -----------------------------------
589 == is the same as
591 |<-texture width ->| /\
592 |111111111111111111|
593 |222222222222222222|texture height
594 |333333333333333333|
595 |444444444444444444| \/
596 --------------------
598 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.
600 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.
602 if (This->Flags & SFLAG_NONPOW2) {
603 BYTE* dataa, *datab;
604 int pitcha = 0, pitchb = 0;
605 int y;
606 pitcha = This->bytesPerPixel * This->currentDesc.Width;
607 pitchb = This->bytesPerPixel * This->pow2Width;
608 datab = dataa = This->resource.allocatedMemory;
609 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, pitcha, pitchb);
610 for (y = 1 ; y < This->currentDesc.Height; y++) {
611 dataa += pitcha; /* skip the first row */
612 datab += pitchb;
613 memcpy(dataa, datab, pitcha);
618 LEAVE_GL();
620 } else { /* Nothing to do */
621 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
624 if (NULL == pRect) {
625 pLockedRect->pBits = This->resource.allocatedMemory;
626 } else{
627 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
628 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
629 } else {
630 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
634 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
635 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
636 GLint prev_store;
637 GLint prev_read;
638 BOOL notInContext = FALSE;
639 IWineD3DSwapChainImpl *targetSwapChain = NULL;
642 ENTER_GL();
645 * for render->surface copy begin to begin of allocatedMemory
646 * unlock can be more easy
649 TRACE("locking a render target\n");
651 if (This->resource.allocatedMemory == NULL)
652 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
654 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
655 pLockedRect->pBits = This->resource.allocatedMemory;
657 glFlush();
658 vcheckGLcall("glFlush");
659 glGetIntegerv(GL_READ_BUFFER, &prev_read);
660 vcheckGLcall("glIntegerv");
661 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
662 vcheckGLcall("glIntegerv");
664 /* Here's what we have to do:
665 See if the swapchain has the same context as the renderTarget or the surface is the render target.
666 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
667 and use the front back buffer as required.
668 if not, we need to switch contexts and then switchback at the end.
670 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
671 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
673 /* 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! */
674 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
675 if (iface == swapchain->frontBuffer) {
676 TRACE("locking front\n");
677 glReadBuffer(GL_FRONT);
679 else if (iface == myDevice->renderTarget || backbuf) {
680 TRACE("locking back buffer\n");
681 glReadBuffer(GL_BACK);
682 } else if (iface == myDevice->depthStencilBuffer) {
683 FIXME("Stencil Buffer lock unsupported for now\n");
684 } else {
685 FIXME("(%p) Shouldn't have got here!\n", This);
686 glReadBuffer(GL_BACK);
688 } else if (swapchain != NULL) {
689 IWineD3DSwapChainImpl *implSwapChain;
690 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
691 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
692 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
693 if (backbuf) {
694 glReadBuffer(GL_BACK);
695 } else if (iface == swapchain->frontBuffer) {
696 glReadBuffer(GL_FRONT);
697 } else if (iface == myDevice->depthStencilBuffer) {
698 FIXME("Stencil Buffer lock unsupported for now\n");
699 } else {
700 FIXME("Should have got here!\n");
701 glReadBuffer(GL_BACK);
703 } else {
704 /* We need to switch contexts to be able to read the buffer!!! */
705 FIXME("The buffer requested isn't in the current openGL context\n");
706 notInContext = TRUE;
707 /* TODO: check the contexts, to see if were shared with the current context */
709 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
711 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
712 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
714 /** the depth stencil in openGL has a format of GL_FLOAT
715 * which should be good for WINED3DFMT_D16_LOCKABLE
716 * and WINED3DFMT_D16
717 * it is unclear what format the stencil buffer is in except.
718 * 'Each index is converted to fixed point...
719 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
720 * mappings in the table GL_PIXEL_MAP_S_TO_S.
721 * glReadPixels(This->lockedRect.left,
722 * This->lockedRect.bottom - j - 1,
723 * This->lockedRect.right - This->lockedRect.left,
724 * 1,
725 * GL_DEPTH_COMPONENT,
726 * type,
727 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
728 *****************************************/
729 if (!notInContext) { /* Only read the buffer if it's in the current context */
730 switch(wined3d_settings.rendertargetlock_mode) {
731 case RTL_AUTO:
732 case RTL_READDRAW:
733 case RTL_READTEX:
734 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
735 break;
737 case RTL_TEXDRAW:
738 case RTL_TEXTEX:
739 ERR("Reading from render target with a texture isn't implemented yet\n");
740 break;
742 case RTL_DISABLE:
744 static BOOL warned = FALSE;
745 if(!warned) {
746 ERR("Application tries to lock the render target, but render target locking is disabled\n");
747 warned = TRUE;
750 break;
753 TRACE("Resetting buffer\n");
755 glReadBuffer(prev_read);
756 vcheckGLcall("glReadBuffer");
758 LEAVE_GL();
760 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
762 if (!messages & 1) {
763 FIXME("TODO stencil depth surface locking surf%p usage(%lu)\n", This, This->resource.usage);
766 glReadPixels(This->lockedRect.left,
767 This->lockedRect.bottom - j - 1,
768 This->lockedRect.right - This->lockedRect.left,
770 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
774 messages |= 1;
776 } else {
777 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->resource.usage);
780 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
781 /* Don't dirtify */
782 } else {
783 IWineD3DBaseTexture *pBaseTexture;
785 * Dirtify on lock
786 * as seen in msdn docs
788 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
790 /** Dirtify Container if needed */
791 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
792 TRACE("Making container dirty\n");
793 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
794 IWineD3DBaseTexture_Release(pBaseTexture);
795 } else {
796 TRACE("Surface is standalone, no need to dirty the container\n");
800 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
802 This->Flags |= SFLAG_LOCKED;
803 return WINED3D_OK;
806 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
807 GLint prev_store;
808 GLint prev_rasterpos[4];
809 GLint skipBytes = 0;
810 BOOL storechanged = FALSE;
811 GLint fmt, type;
812 void *mem;
814 glDisable(GL_TEXTURE_2D);
815 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
816 glDisable(GL_TEXTURE_1D);
817 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
819 glFlush();
820 vcheckGLcall("glFlush");
821 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
822 vcheckGLcall("glIntegerv");
823 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
824 vcheckGLcall("glIntegerv");
825 glPixelZoom(1.0, -1.0);
826 vcheckGLcall("glPixelZoom");
828 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
829 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
830 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
832 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
833 vcheckGLcall("glRasterPos2f");
835 /* Some drivers(radeon dri, others?) don't like exceptions during
836 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
837 * after ReleaseDC. Reading it will cause an exception, which x11drv will
838 * catch to put the dib section in InSync mode, which leads to a crash
839 * and a blocked x server on my radeon card.
841 * The following lines read the dib section so it is put in inSync mode
842 * before glDrawPixels is called and the crash is prevented. There won't
843 * be any interfering gdi accesses, because UnlockRect is called from
844 * ReleaseDC, and the app won't use the dc any more afterwards.
846 if(This->Flags & SFLAG_DIBSECTION) {
847 volatile BYTE read;
848 read = This->resource.allocatedMemory[0];
851 switch (This->resource.format) {
852 /* No special care needed */
853 case WINED3DFMT_A4R4G4B4:
854 case WINED3DFMT_R5G6B5:
855 case WINED3DFMT_A1R5G5B5:
856 case WINED3DFMT_R8G8B8:
857 type = This->glDescription.glType;
858 fmt = This->glDescription.glFormat;
859 mem = This->resource.allocatedMemory;
860 break;
862 case WINED3DFMT_X4R4G4B4:
864 int size;
865 unsigned short *data;
866 data = (unsigned short *)This->resource.allocatedMemory;
867 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
868 while(size > 0) {
869 *data |= 0xF000;
870 data++;
871 size--;
873 type = This->glDescription.glType;
874 fmt = This->glDescription.glFormat;
875 mem = This->resource.allocatedMemory;
877 break;
879 case WINED3DFMT_X1R5G5B5:
881 int size;
882 unsigned short *data;
883 data = (unsigned short *)This->resource.allocatedMemory;
884 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
885 while(size > 0) {
886 *data |= 0x8000;
887 data++;
888 size--;
890 type = This->glDescription.glType;
891 fmt = This->glDescription.glFormat;
892 mem = This->resource.allocatedMemory;
894 break;
896 case WINED3DFMT_X8R8G8B8:
898 /* make sure the X byte is set to alpha on, since it
899 could be any random value this fixes the intro move in Pirates! */
900 int size;
901 unsigned int *data;
902 data = (unsigned int *)This->resource.allocatedMemory;
903 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
904 while(size > 0) {
905 *data |= 0xFF000000;
906 data++;
907 size--;
910 /* Fall trough */
912 case WINED3DFMT_A8R8G8B8:
914 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
915 vcheckGLcall("glPixelStorei");
916 storechanged = TRUE;
917 type = This->glDescription.glType;
918 fmt = This->glDescription.glFormat;
919 mem = This->resource.allocatedMemory;
921 break;
923 case WINED3DFMT_A2R10G10B10:
925 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
926 vcheckGLcall("glPixelStorei");
927 storechanged = TRUE;
928 type = This->glDescription.glType;
929 fmt = This->glDescription.glFormat;
930 mem = This->resource.allocatedMemory;
932 break;
934 case WINED3DFMT_P8:
936 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
937 int row;
938 type = GL_UNSIGNED_BYTE;
939 fmt = GL_RGBA;
941 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
942 if(!mem) {
943 ERR("Out of memory\n");
944 return;
946 for(row = This->dirtyRect.top; row < This->dirtyRect.bottom; row++) {
947 d3dfmt_convert_surface(This->resource.allocatedMemory + row * pitch + This->lockedRect.left,
948 (BYTE *) mem + row * pitch * 4 + This->lockedRect.left * 4,
949 This->lockedRect.right - This->lockedRect.left,
950 CONVERT_PALETTED, This);
953 break;
955 default:
956 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
958 /* Give it a try */
959 type = This->glDescription.glType;
960 fmt = This->glDescription.glFormat;
961 mem = This->resource.allocatedMemory;
964 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
965 (This->lockedRect.bottom - This->lockedRect.top)-1,
966 fmt, type,
967 mem);
968 checkGLcall("glDrawPixels");
969 glPixelZoom(1.0,1.0);
970 vcheckGLcall("glPixelZoom");
972 glRasterPos3iv(&prev_rasterpos[0]);
973 vcheckGLcall("glRasterPos3iv");
975 /* Reset to previous pack row length */
976 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
977 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
978 if(storechanged) {
979 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
980 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
983 if(mem != This->resource.allocatedMemory) HeapFree(GetProcessHeap(), 0, mem);
984 return;
987 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
988 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
989 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
990 const char *buffername = "";
991 IWineD3DSwapChainImpl *swapchain = NULL;
992 BOOL backbuf = FALSE;
994 if (!(This->Flags & SFLAG_LOCKED)) {
995 WARN("trying to Unlock an unlocked surf@%p\n", This);
996 return WINED3DERR_INVALIDCALL;
999 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
1000 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1002 if(swapchain) {
1003 int i;
1004 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
1005 if(iface == swapchain->backBuffer[i]) {
1006 backbuf = TRUE;
1007 break;
1012 if (backbuf) {
1013 buffername = "backBuffer";
1014 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
1015 buffername = "frontBuffer";
1016 } else if (iface == myDevice->depthStencilBuffer) {
1017 buffername = "depthStencilBuffer";
1018 } else if (iface == myDevice->renderTarget) {
1019 buffername = "renderTarget";
1023 if (swapchain != NULL) {
1024 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1027 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
1029 if (!(This->Flags & SFLAG_DIRTY)) {
1030 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1031 goto unlock_end;
1034 if (0 == This->resource.usage) { /* classic surface */
1036 * nothing to do
1037 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
1039 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
1041 /****************************
1042 * TODO: Render targets are 'special' and
1043 * ?some? locking needs to be passed onto the context manager
1044 * so that it becomes possible to use auxiliary buffers, pbuffers
1045 * render-to-texture, shared, cached contexts etc...
1046 * ****************************/
1047 IWineD3DSwapChainImpl *implSwapChain;
1048 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
1050 if (backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
1051 int tex;
1053 ENTER_GL();
1055 /* glDrawPixels transforms the raster position as though it was a vertex -
1056 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1057 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1058 d3ddevice_set_ortho(This->resource.wineD3DDevice);
1060 if (iface == implSwapChain->frontBuffer) {
1061 glDrawBuffer(GL_FRONT);
1062 checkGLcall("glDrawBuffer GL_FRONT");
1063 } else if (backbuf || iface == myDevice->renderTarget) {
1064 glDrawBuffer(GL_BACK);
1065 checkGLcall("glDrawBuffer GL_BACK");
1068 /* Disable higher textures before calling glDrawPixels */
1069 for(tex = 1; tex < GL_LIMITS(sampler_stages); tex++) {
1070 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1071 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + tex));
1072 checkGLcall("glActiveTextureARB");
1074 glDisable(GL_TEXTURE_2D);
1075 checkGLcall("glDisable GL_TEXTURE_2D");
1076 glDisable(GL_TEXTURE_1D);
1077 checkGLcall("glDisable GL_TEXTURE_1D");
1079 /* Activate texture 0, but don't disable it necessarilly */
1080 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1081 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1082 checkGLcall("glActiveTextureARB");
1085 /* And back buffers are not blended. Disable the depth test,
1086 that helps performance */
1087 glDisable(GL_BLEND);
1088 glDisable(GL_DEPTH_TEST);
1089 glDisable(GL_FOG);
1091 switch(wined3d_settings.rendertargetlock_mode) {
1092 case RTL_AUTO:
1093 case RTL_READDRAW:
1094 case RTL_TEXDRAW:
1095 flush_to_framebuffer_drawpixels(This);
1096 break;
1098 case RTL_READTEX:
1099 case RTL_TEXTEX:
1100 ERR("Writing to the render target with textures is not implemented yet\n");
1101 break;
1103 case RTL_DISABLE:
1105 static BOOL warned = FALSE;
1106 if(!warned) {
1107 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1108 warned = TRUE;
1111 break;
1114 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1115 glDrawBuffer(GL_BACK);
1116 vcheckGLcall("glDrawBuffer");
1118 if(myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_TRUE ||
1119 myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_USEW) glEnable(GL_DEPTH_TEST);
1120 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1121 if (myDevice->stateBlock->renderState[D3DRS_FOGENABLE]) glEnable(GL_FOG);
1123 LEAVE_GL();
1125 /** restore clean dirty state */
1126 IWineD3DSurface_CleanDirtyRect(iface);
1128 } else {
1129 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1131 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1133 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1135 if (iface == myDevice->depthStencilBuffer) {
1136 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->resource.usage);
1137 } else {
1138 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->resource.usage);
1141 } else {
1142 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1145 unlock_end:
1146 This->Flags &= ~SFLAG_LOCKED;
1147 memset(&This->lockedRect, 0, sizeof(RECT));
1148 return WINED3D_OK;
1151 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1152 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1153 WINED3DLOCKED_RECT lock;
1154 UINT usage;
1155 BITMAPINFO* b_info;
1156 HDC ddc;
1157 DWORD *masks;
1158 HRESULT hr;
1159 RGBQUAD col[256];
1160 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1162 TRACE("(%p)->(%p)\n",This,pHDC);
1164 /* Give more detailed info for ddraw */
1165 if (This->Flags & SFLAG_DCINUSE)
1166 return DDERR_DCALREADYCREATED;
1168 /* Can't GetDC if the surface is locked */
1169 if (This->Flags & SFLAG_LOCKED)
1170 return WINED3DERR_INVALIDCALL;
1172 memset(&lock, 0, sizeof(lock)); /* To be sure */
1174 /* Create a DIB section if there isn't a hdc yet */
1175 if(!This->hDC) {
1176 int extraline = 0;
1177 SYSTEM_INFO sysInfo;
1179 if(This->Flags & SFLAG_ACTIVELOCK) {
1180 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1183 switch (This->bytesPerPixel) {
1184 case 2:
1185 case 4:
1186 /* Allocate extra space to store the RGB bit masks. */
1187 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1188 break;
1190 case 3:
1191 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1192 break;
1194 default:
1195 /* Allocate extra space for a palette. */
1196 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1197 sizeof(BITMAPINFOHEADER)
1198 + sizeof(RGBQUAD)
1199 * (1 << (This->bytesPerPixel * 8)));
1200 break;
1203 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1204 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1205 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1206 * add an extra line to the dib section
1208 GetSystemInfo(&sysInfo);
1209 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1210 extraline = 1;
1211 TRACE("Adding an extra line to the dib section\n");
1214 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1215 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1216 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1217 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1218 b_info->bmiHeader.biSizeImage = This->currentDesc.Width * This->currentDesc.Height * This->bytesPerPixel;
1219 /* Use the full pow2 image size(assigned below) because LockRect
1220 * will need it for a full glGetTexImage call
1222 } else {
1223 b_info->bmiHeader.biWidth = This->pow2Width;
1224 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1225 b_info->bmiHeader.biSizeImage = This->resource.size;
1227 b_info->bmiHeader.biPlanes = 1;
1228 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1230 b_info->bmiHeader.biXPelsPerMeter = 0;
1231 b_info->bmiHeader.biYPelsPerMeter = 0;
1232 b_info->bmiHeader.biClrUsed = 0;
1233 b_info->bmiHeader.biClrImportant = 0;
1235 /* Get the bit masks */
1236 masks = (DWORD *) &(b_info->bmiColors);
1237 switch (This->resource.format) {
1238 case WINED3DFMT_R8G8B8:
1239 usage = DIB_RGB_COLORS;
1240 b_info->bmiHeader.biCompression = BI_RGB;
1241 break;
1243 case WINED3DFMT_X1R5G5B5:
1244 case WINED3DFMT_A1R5G5B5:
1245 case WINED3DFMT_A4R4G4B4:
1246 case WINED3DFMT_X4R4G4B4:
1247 case WINED3DFMT_R3G3B2:
1248 case WINED3DFMT_A8R3G3B2:
1249 case WINED3DFMT_A2B10G10R10:
1250 case WINED3DFMT_A8B8G8R8:
1251 case WINED3DFMT_X8B8G8R8:
1252 case WINED3DFMT_A2R10G10B10:
1253 case WINED3DFMT_R5G6B5:
1254 case WINED3DFMT_A16B16G16R16:
1255 usage = 0;
1256 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1257 masks[0] = formatEntry->redMask;
1258 masks[1] = formatEntry->greenMask;
1259 masks[2] = formatEntry->blueMask;
1260 break;
1262 default:
1263 /* Don't know palette */
1264 b_info->bmiHeader.biCompression = BI_RGB;
1265 usage = 0;
1266 break;
1269 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1270 if (ddc == 0) {
1271 HeapFree(GetProcessHeap(), 0, b_info);
1272 return HRESULT_FROM_WIN32(GetLastError());
1275 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);
1276 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1277 DeleteDC(ddc);
1279 if (!This->dib.DIBsection) {
1280 ERR("CreateDIBSection failed!\n");
1281 return HRESULT_FROM_WIN32(GetLastError());
1283 HeapFree(GetProcessHeap(), 0, b_info);
1285 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1287 /* copy the existing surface to the dib section */
1288 if(This->resource.allocatedMemory) {
1289 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1290 /* We won't need that any more */
1291 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1292 } else {
1293 /* This is to make LockRect read the gl Texture although memory is allocated */
1294 This->Flags |= SFLAG_GLDIRTY;
1297 /* Use the dib section from now on */
1298 This->resource.allocatedMemory = This->dib.bitmap_data;
1300 /* Now allocate a HDC */
1301 This->hDC = CreateCompatibleDC(0);
1302 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1303 TRACE("using wined3d palette %p\n", This->palette);
1304 SelectPalette(This->hDC,
1305 This->palette ? This->palette->hpal : 0,
1306 FALSE);
1308 This->Flags |= SFLAG_DIBSECTION;
1311 /* Lock the surface */
1312 hr = IWineD3DSurface_LockRect(iface,
1313 &lock,
1314 NULL,
1316 if(FAILED(hr)) {
1317 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1318 /* keep the dib section */
1319 return hr;
1322 if(This->resource.format == WINED3DFMT_P8 ||
1323 This->resource.format == WINED3DFMT_A8P8) {
1324 unsigned int n;
1325 if(This->palette) {
1326 PALETTEENTRY ent[256];
1328 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1329 for (n=0; n<256; n++) {
1330 col[n].rgbRed = ent[n].peRed;
1331 col[n].rgbGreen = ent[n].peGreen;
1332 col[n].rgbBlue = ent[n].peBlue;
1333 col[n].rgbReserved = 0;
1335 } else {
1336 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1338 for (n=0; n<256; n++) {
1339 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1340 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1341 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1342 col[n].rgbReserved = 0;
1346 SetDIBColorTable(This->hDC, 0, 256, col);
1349 *pHDC = This->hDC;
1350 TRACE("returning %p\n",*pHDC);
1351 This->Flags |= SFLAG_DCINUSE;
1353 return WINED3D_OK;
1356 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1357 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1359 TRACE("(%p)->(%p)\n",This,hDC);
1361 if (!(This->Flags & SFLAG_DCINUSE))
1362 return D3DERR_INVALIDCALL;
1364 /* we locked first, so unlock now */
1365 IWineD3DSurface_UnlockRect(iface);
1367 This->Flags &= ~SFLAG_DCINUSE;
1369 return WINED3D_OK;
1372 /* ******************************************************
1373 IWineD3DSurface Internal (No mapping to directx api) parts follow
1374 ****************************************************** */
1376 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1377 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1378 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1380 /* Default values: From the surface */
1381 *format = formatEntry->glFormat;
1382 *internal = formatEntry->glInternal;
1383 *type = formatEntry->glType;
1384 *convert = NO_CONVERSION;
1385 *target_bpp = This->bytesPerPixel;
1387 /* Ok, now look if we have to do any conversion */
1388 switch(This->resource.format) {
1389 case WINED3DFMT_P8:
1390 /* ****************
1391 Paletted Texture
1392 **************** */
1393 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active) {
1394 *format = GL_RGBA;
1395 *internal = GL_RGBA;
1396 *type = GL_UNSIGNED_BYTE;
1397 *target_bpp = 4;
1398 if(colorkey_active) {
1399 *convert = CONVERT_PALETTED;
1400 } else {
1401 *convert = CONVERT_PALETTED_CK;
1405 break;
1407 case WINED3DFMT_R3G3B2:
1408 /* **********************
1409 GL_UNSIGNED_BYTE_3_3_2
1410 ********************** */
1411 if (colorkey_active) {
1412 /* This texture format will never be used.. So do not care about color keying
1413 up until the point in time it will be needed :-) */
1414 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1416 break;
1418 case WINED3DFMT_R5G6B5:
1419 if (colorkey_active) {
1420 *convert = CONVERT_CK_565;
1421 *format = GL_RGBA;
1422 *internal = GL_RGBA;
1423 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1425 break;
1427 case WINED3DFMT_R8G8B8:
1428 if (colorkey_active) {
1429 *convert = CONVERT_CK_RGB24;
1430 *format = GL_RGBA;
1431 *internal = GL_RGBA;
1432 *type = GL_UNSIGNED_INT_8_8_8_8;
1433 *target_bpp = 4;
1435 break;
1437 case WINED3DFMT_X8R8G8B8:
1438 if (colorkey_active) {
1439 *convert = CONVERT_RGB32_888;
1440 *format = GL_RGBA;
1441 *internal = GL_RGBA;
1442 *type = GL_UNSIGNED_INT_8_8_8_8;
1444 break;
1445 #if 0
1446 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1447 case WINED3DFMT_A4R4G4B4:
1448 if (colorkey_active)
1450 *convert = CONVERT_CK_4444_ARGB;
1451 *format = GL_RGBA;
1452 *internal = GL_RGBA;
1453 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1455 break;
1457 case WINED3DFMT_A1R5G5B5:
1458 if (colorkey_active)
1460 *convert = CONVERT_CK_1555;
1463 case WINED3DFMT_A8R8G8B8:
1464 if (colorkey_active)
1466 *convert = CONVERT_CK_8888_ARGB;
1467 *format = GL_RGBA;
1468 *internal = GL_RGBA;
1469 *type = GL_UNSIGNED_INT_8_8_8_8;
1471 break;
1472 #endif
1473 default:
1474 break;
1477 return WINED3D_OK;
1480 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1481 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1483 switch (convert) {
1484 case NO_CONVERSION:
1486 memcpy(dst, src, len * surf->bytesPerPixel);
1487 break;
1489 case CONVERT_PALETTED:
1490 case CONVERT_PALETTED_CK:
1492 IWineD3DPaletteImpl* pal = surf->palette;
1493 BYTE table[256][4];
1494 unsigned int i;
1495 unsigned int x;
1497 if( pal == NULL) {
1498 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1501 if (pal == NULL) {
1502 /* Still no palette? Use the device's palette */
1503 /* Get the surface's palette */
1504 for (i = 0; i < 256; i++) {
1505 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1507 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1508 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1509 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1510 if ((convert == CONVERT_PALETTED_CK) &&
1511 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1512 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1513 /* We should maybe here put a more 'neutral' color than the standard bright purple
1514 one often used by application to prevent the nice purple borders when bi-linear
1515 filtering is on */
1516 table[i][3] = 0x00;
1517 } else {
1518 table[i][3] = 0xFF;
1521 } else {
1522 TRACE("Using surface palette %p\n", pal);
1523 /* Get the surface's palette */
1524 for (i = 0; i < 256; i++) {
1525 table[i][0] = pal->palents[i].peRed;
1526 table[i][1] = pal->palents[i].peGreen;
1527 table[i][2] = pal->palents[i].peBlue;
1528 if ((convert == CONVERT_PALETTED_CK) &&
1529 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1530 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1531 /* We should maybe here put a more 'neutral' color than the standard bright purple
1532 one often used by application to prevent the nice purple borders when bi-linear
1533 filtering is on */
1534 table[i][3] = 0x00;
1535 } else {
1536 table[i][3] = 0xFF;
1541 for (x = 0; x < len; x++) {
1542 BYTE color = *src++;
1543 *dst++ = table[color][0];
1544 *dst++ = table[color][1];
1545 *dst++ = table[color][2];
1546 *dst++ = table[color][3];
1549 break;
1551 case CONVERT_CK_565:
1553 /* Converting the 565 format in 5551 packed to emulate color-keying.
1555 Note : in all these conversion, it would be best to average the averaging
1556 pixels to get the color of the pixel that will be color-keyed to
1557 prevent 'color bleeding'. This will be done later on if ever it is
1558 too visible.
1560 Note2: when using color-keying + alpha, are the alpha bits part of the
1561 color-space or not ?
1563 unsigned int x;
1564 WORD *Source = (WORD *) src;
1565 WORD *Dest = (WORD *) dst;
1567 TRACE("Color keyed 565\n");
1569 for (x = 0; x < len; x++ ) {
1570 WORD color = *Source++;
1571 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1572 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1573 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1574 *Dest |= 0x0001;
1576 Dest++;
1579 break;
1581 case CONVERT_CK_1555:
1583 unsigned int x;
1584 WORD *Source = (WORD *) src;
1585 WORD *Dest = (WORD *) dst;
1587 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1588 WORD color = *Source++;
1589 *Dest = (color & 0x7FFF);
1590 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1591 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1592 *Dest |= (color & 0x8000);
1593 Dest++;
1596 break;
1598 case CONVERT_CK_4444_ARGB:
1600 /* Move the four Alpha bits... */
1601 unsigned int x;
1602 WORD *Source = (WORD *) src;
1603 WORD *Dest = (WORD *) dst;
1605 for (x = 0; x < len; x++) {
1606 WORD color = *Source++;
1607 *dst = (color & 0x0FFF) << 4;
1608 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1609 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1610 *Dest |= (color & 0xF000) >> 12;
1611 Dest++;
1613 } break;
1615 default:
1616 ERR("Unsupported conversation type %d\n", convert);
1619 return WINED3D_OK;
1622 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1623 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1625 if (This->Flags & SFLAG_INTEXTURE) {
1626 TRACE("Surface already in texture\n");
1627 return WINED3D_OK;
1629 if (!(This->Flags & SFLAG_DIRTY)) {
1630 TRACE("surface isn't dirty\n");
1631 return WINED3D_OK;
1634 This->Flags &= ~SFLAG_DIRTY;
1636 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1637 * These resources are not bound by device size or format restrictions. Because of this,
1638 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1639 * However, these resources can always be created, locked, and copied.
1641 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1643 FIXME("(%p) Operation not supported for scratch textures\n",This);
1644 return WINED3DERR_INVALIDCALL;
1647 if (This->Flags & SFLAG_INPBUFFER) {
1648 ENTER_GL();
1650 if (This->glDescription.level != 0)
1651 FIXME("Surface in texture is only supported for level 0\n");
1652 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1653 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1654 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1655 This->resource.format == WINED3DFMT_DXT5)
1656 FIXME("Format %d not supported\n", This->resource.format);
1657 else {
1658 GLint prevRead;
1659 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1660 vcheckGLcall("glGetIntegerv");
1661 glReadBuffer(GL_BACK);
1662 vcheckGLcall("glReadBuffer");
1664 glCopyTexImage2D(This->glDescription.target,
1665 This->glDescription.level,
1666 This->glDescription.glFormatInternal,
1669 This->currentDesc.Width,
1670 This->currentDesc.Height,
1673 checkGLcall("glCopyTexImage2D");
1674 glReadBuffer(prevRead);
1675 vcheckGLcall("glReadBuffer");
1676 TRACE("Updating target %d\n", This->glDescription.target);
1677 This->Flags |= SFLAG_INTEXTURE;
1679 LEAVE_GL();
1680 return WINED3D_OK;
1683 /* TODO: Compressed non-power 2 support */
1685 if (This->resource.format == WINED3DFMT_DXT1 ||
1686 This->resource.format == WINED3DFMT_DXT2 ||
1687 This->resource.format == WINED3DFMT_DXT3 ||
1688 This->resource.format == WINED3DFMT_DXT4 ||
1689 This->resource.format == WINED3DFMT_DXT5) {
1690 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
1691 FIXME("Using DXT1/3/5 without advertized support\n");
1692 } else if (This->resource.allocatedMemory) {
1693 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
1694 This->glDescription.target,
1695 This->glDescription.level,
1696 This->glDescription.glFormatInternal,
1697 This->currentDesc.Width,
1698 This->currentDesc.Height,
1700 This->resource.size,
1701 This->resource.allocatedMemory);
1703 ENTER_GL();
1705 GL_EXTCALL(glCompressedTexImage2DARB)(This->glDescription.target,
1706 This->glDescription.level,
1707 This->glDescription.glFormatInternal,
1708 This->currentDesc.Width,
1709 This->currentDesc.Height,
1711 This->resource.size,
1712 This->resource.allocatedMemory);
1713 checkGLcall("glCommpressedTexImage2D");
1715 LEAVE_GL();
1717 if(!(This->Flags & SFLAG_DONOTFREE)){
1718 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1719 This->resource.allocatedMemory = NULL;
1722 } else {
1723 GLenum format, internal, type;
1724 CONVERT_TYPES convert;
1725 int bpp;
1726 BYTE *mem;
1728 d3dfmt_get_conv(This, TRUE /* We need color keying */, &format, &internal, &type, &convert, &bpp);
1730 if((convert != NO_CONVERSION) &&
1731 This->resource.allocatedMemory) {
1732 int width = This->glRect.right - This->glRect.left;
1733 int height = This->glRect.bottom - This->glRect.top;
1734 int row;
1736 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
1737 if(!mem) {
1738 ERR("Out of memory %d, %d!\n", width, height);
1739 return WINED3DERR_OUTOFVIDEOMEMORY;
1742 for(row = This->glRect.top; row < This->glRect.bottom; row++) {
1743 BYTE *cur = This->resource.allocatedMemory + row * This->pow2Width * This->bytesPerPixel;
1744 d3dfmt_convert_surface(cur + This->glRect.left * This->bytesPerPixel,
1745 mem + row * width * bpp,
1746 width,
1747 convert,
1748 This);
1750 This->Flags |= SFLAG_CONVERTED;
1751 } else {
1752 This->Flags &= ~SFLAG_CONVERTED;
1753 mem = This->resource.allocatedMemory;
1756 /* TODO: possibly use texture rectangle (though we are probably more compatible without it) */
1757 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE) ) {
1760 TRACE("non power of two support\n");
1761 ENTER_GL();
1762 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,
1763 This->glDescription.target,
1764 This->glDescription.level,
1765 debug_d3dformat(This->resource.format),
1766 This->glDescription.glFormatInternal,
1767 This->pow2Width,
1768 This->pow2Height,
1770 This->glDescription.glFormat,
1771 This->glDescription.glType,
1772 NULL);
1774 glTexImage2D(This->glDescription.target,
1775 This->glDescription.level,
1776 This->glDescription.glFormatInternal,
1777 This->pow2Width,
1778 This->pow2Height,
1779 0/*border*/,
1780 This->glDescription.glFormat,
1781 This->glDescription.glType,
1782 NULL);
1784 checkGLcall("glTexImage2D");
1785 if (This->resource.allocatedMemory != NULL) {
1786 TRACE("(%p) Calling glTexSubImage2D w(%d) h(%d) mem(%p)\n", This, This->currentDesc.Width, This->currentDesc.Height, This->resource.allocatedMemory);
1787 /* And map the non-power two data into the top left corner */
1788 glTexSubImage2D(
1789 This->glDescription.target,
1790 This->glDescription.level,
1791 0 /* xoffset */,
1792 0 /* ysoffset */ ,
1793 This->currentDesc.Width,
1794 This->currentDesc.Height,
1795 This->glDescription.glFormat,
1796 This->glDescription.glType,
1797 This->resource.allocatedMemory
1799 checkGLcall("glTexSubImage2D");
1801 LEAVE_GL();
1803 } else {
1805 TRACE("Calling 2 glTexImage2D %x i=%d, d3dfmt=%s, intfmt=%x, w=%ld, h=%ld,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
1806 This->glDescription.target,
1807 This->glDescription.level,
1808 debug_d3dformat(This->resource.format),
1809 This->glDescription.glFormatInternal,
1810 This->glRect.right - This->glRect.left,
1811 This->glRect.bottom - This->glRect.top,
1813 This->glDescription.glFormat,
1814 This->glDescription.glType,
1815 mem);
1817 ENTER_GL();
1819 /* OK, create the texture */
1820 glTexImage2D(This->glDescription.target,
1821 This->glDescription.level,
1822 internal,
1823 This->glRect.right - This->glRect.left,
1824 This->glRect.bottom - This->glRect.top,
1825 0 /* border */,
1826 format,
1827 type,
1828 mem);
1830 checkGLcall("glTexImage2D");
1832 LEAVE_GL();
1834 if(mem != This->resource.allocatedMemory)
1835 HeapFree(GetProcessHeap(), 0, mem);
1837 #if 0
1839 static unsigned int gen = 0;
1840 char buffer[4096];
1841 ++gen;
1842 if ((gen % 10) == 0) {
1843 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1844 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1847 * debugging crash code
1848 if (gen == 250) {
1849 void** test = NULL;
1850 *test = 0;
1854 #endif
1855 if(!(This->Flags & SFLAG_DONOTFREE)){
1856 HeapFree(GetProcessHeap(),0,This->resource.allocatedMemory);
1857 This->resource.allocatedMemory = NULL;
1862 return WINED3D_OK;
1865 #include <errno.h>
1866 #include <stdio.h>
1867 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1868 FILE* f = NULL;
1869 UINT i, y;
1870 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1871 char *allocatedMemory;
1872 char *textureRow;
1873 IWineD3DSwapChain *swapChain = NULL;
1874 int width, height;
1875 GLuint tmpTexture;
1876 DWORD color;
1877 /*FIXME:
1878 Textures my not be stored in ->allocatedgMemory and a GlTexture
1879 so we should lock the surface before saving a snapshot, or at least check that
1881 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1882 by calling GetTexImage and in compressed form by calling
1883 GetCompressedTexImageARB. Queried compressed images can be saved and
1884 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1885 texture images do not need to be processed by the GL and should
1886 significantly improve texture loading performance relative to uncompressed
1887 images. */
1889 /* Setup the width and height to be the internal texture width and height. */
1890 width = This->pow2Width;
1891 height = This->pow2Height;
1892 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1893 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1895 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1896 /* 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 */
1897 GLint prevRead;
1898 ENTER_GL();
1899 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1900 glEnable(GL_TEXTURE_2D);
1902 glGenTextures(1, &tmpTexture);
1903 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1905 glTexImage2D(GL_TEXTURE_2D,
1907 GL_RGBA,
1908 width,
1909 height,
1910 0/*border*/,
1911 GL_RGBA,
1912 GL_UNSIGNED_INT_8_8_8_8_REV,
1913 NULL);
1915 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1916 vcheckGLcall("glGetIntegerv");
1917 glReadBuffer(GL_BACK);
1918 vcheckGLcall("glReadBuffer");
1919 glCopyTexImage2D(GL_TEXTURE_2D,
1921 GL_RGBA,
1924 width,
1925 height,
1928 checkGLcall("glCopyTexImage2D");
1929 glReadBuffer(prevRead);
1930 LEAVE_GL();
1932 } else { /* bind the real texture */
1933 IWineD3DSurface_PreLoad(iface);
1935 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1936 ENTER_GL();
1937 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1938 glGetTexImage(GL_TEXTURE_2D,
1939 This->glDescription.level,
1940 GL_RGBA,
1941 GL_UNSIGNED_INT_8_8_8_8_REV,
1942 allocatedMemory);
1943 checkGLcall("glTexImage2D");
1944 if (tmpTexture) {
1945 glBindTexture(GL_TEXTURE_2D, 0);
1946 glDeleteTextures(1, &tmpTexture);
1948 LEAVE_GL();
1950 f = fopen(filename, "w+");
1951 if (NULL == f) {
1952 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1953 return WINED3DERR_INVALIDCALL;
1955 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1956 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
1957 /* TGA header */
1958 fputc(0,f);
1959 fputc(0,f);
1960 fputc(2,f);
1961 fputc(0,f);
1962 fputc(0,f);
1963 fputc(0,f);
1964 fputc(0,f);
1965 fputc(0,f);
1966 fputc(0,f);
1967 fputc(0,f);
1968 fputc(0,f);
1969 fputc(0,f);
1970 /* short width*/
1971 fwrite(&width,2,1,f);
1972 /* short height */
1973 fwrite(&height,2,1,f);
1974 /* format rgba */
1975 fputc(0x20,f);
1976 fputc(0x28,f);
1977 /* raw data */
1978 /* 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*/
1979 if(swapChain)
1980 textureRow = allocatedMemory + (width * (height - 1) *4);
1981 else
1982 textureRow = allocatedMemory;
1983 for (y = 0 ; y < height; y++) {
1984 for (i = 0; i < width; i++) {
1985 color = *((DWORD*)textureRow);
1986 fputc((color >> 16) & 0xFF, f); /* B */
1987 fputc((color >> 8) & 0xFF, f); /* G */
1988 fputc((color >> 0) & 0xFF, f); /* R */
1989 fputc((color >> 24) & 0xFF, f); /* A */
1990 textureRow += 4;
1992 /* take two rows of the pointer to the texture memory */
1993 if(swapChain)
1994 (textureRow-= width << 3);
1997 TRACE("Closing file\n");
1998 fclose(f);
2000 if(swapChain) {
2001 IWineD3DSwapChain_Release(swapChain);
2003 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2004 return WINED3D_OK;
2007 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2008 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2009 This->Flags &= ~SFLAG_DIRTY;
2010 This->dirtyRect.left = This->currentDesc.Width;
2011 This->dirtyRect.top = This->currentDesc.Height;
2012 This->dirtyRect.right = 0;
2013 This->dirtyRect.bottom = 0;
2014 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2015 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2016 return WINED3D_OK;
2020 * Slightly inefficient way to handle multiple dirty rects but it works :)
2022 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2023 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2024 IWineD3DBaseTexture *baseTexture = NULL;
2025 This->Flags |= SFLAG_DIRTY;
2026 if (NULL != pDirtyRect) {
2027 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2028 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2029 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2030 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2031 } else {
2032 This->dirtyRect.left = 0;
2033 This->dirtyRect.top = 0;
2034 This->dirtyRect.right = This->currentDesc.Width;
2035 This->dirtyRect.bottom = This->currentDesc.Height;
2037 TRACE("(%p) : Dirty?%ld, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2038 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2039 /* if the container is a basetexture then mark it dirty. */
2040 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2041 TRACE("Passing to conatiner\n");
2042 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2043 IWineD3DBaseTexture_Release(baseTexture);
2045 return WINED3D_OK;
2048 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2049 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2051 TRACE("This %p, container %p\n", This, container);
2053 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2055 TRACE("Setting container to %p from %p\n", container, This->container);
2056 This->container = container;
2058 return WINED3D_OK;
2061 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2062 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2063 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2065 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2066 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2067 return WINED3DERR_INVALIDCALL;
2070 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2071 if (format == WINED3DFMT_UNKNOWN) {
2072 This->resource.size = 0;
2073 } else if (format == WINED3DFMT_DXT1) {
2074 /* DXT1 is half byte per pixel */
2075 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2077 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2078 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2079 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2080 } else {
2081 This->resource.size = (This->pow2Width * formatEntry->bpp) * This->pow2Height;
2085 /* Setup some glformat defaults */
2086 This->glDescription.glFormat = formatEntry->glFormat;
2087 This->glDescription.glFormatInternal = formatEntry->glInternal;
2088 This->glDescription.glType = formatEntry->glType;
2090 if (format != WINED3DFMT_UNKNOWN) {
2091 This->bytesPerPixel = formatEntry->bpp;
2092 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2093 } else {
2094 This->bytesPerPixel = 0;
2095 This->pow2Size = 0;
2098 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2100 This->resource.format = format;
2102 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);
2104 return WINED3D_OK;
2107 /* TODO: replace this function with context management routines */
2108 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2109 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2111 if(inPBuffer) {
2112 This->Flags |= SFLAG_INPBUFFER;
2113 } else {
2114 This->Flags &= ~SFLAG_INPBUFFER;
2117 if(inTexture) {
2118 This->Flags |= SFLAG_INTEXTURE;
2119 } else {
2120 This->Flags &= ~SFLAG_INTEXTURE;
2123 return WINED3D_OK;
2126 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2127 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2128 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2129 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
2131 /* Flipping is only supported on RenderTargets */
2132 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2134 if(override) {
2135 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2136 * FIXME("(%p) Target override is not supported by now\n", This);
2137 * Additionally, it isn't really possible to support triple-buffering
2138 * properly on opengl at all
2142 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2143 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2146 /* Not called from the VTable */
2147 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2148 D3DRECT rect;
2149 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2150 IWineD3DSwapChainImpl *swapchain = NULL;
2151 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2152 BOOL SrcOK = TRUE;
2154 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2156 /* Get the swapchain. One of the surfaces has to be a primary surface */
2157 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2158 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2159 else if(Src) {
2160 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2161 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2162 else return WINED3DERR_INVALIDCALL;
2163 } else {
2164 swapchain = NULL;
2167 if (DestRect) {
2168 rect.x1 = DestRect->left;
2169 rect.y1 = DestRect->top;
2170 rect.x2 = DestRect->right;
2171 rect.y2 = DestRect->bottom;
2172 } else {
2173 rect.x1 = 0;
2174 rect.y1 = 0;
2175 rect.x2 = This->currentDesc.Width;
2176 rect.y2 = This->currentDesc.Height;
2179 /* Half-life does a Blt from the back buffer to the front buffer,
2180 * Full surface size, no flags... Use present instead
2182 if(Src)
2184 /* First, check if we can do a Flip */
2186 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2187 if( SrcRect ) {
2188 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2189 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2190 SrcOK = TRUE;
2192 } else {
2193 SrcOK = TRUE;
2196 /* Check the Destination rect and the surface sizes */
2197 if(SrcOK &&
2198 (rect.x1 == 0) && (rect.y1 == 0) &&
2199 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2200 (This->currentDesc.Width == Src->currentDesc.Width) &&
2201 (This->currentDesc.Height == Src->currentDesc.Height)) {
2202 /* These flags are unimportant for the flag check, remove them */
2204 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2205 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2207 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2209 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2210 * take very long, while a flip is fast.
2211 * This applies to Half-Life, which does such Blts every time it finished
2212 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2213 * menu. This is also used by all apps when they do windowed rendering
2215 * The problem is that flipping is not really the same as copying. After a
2216 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2217 * untouched. Therefore it's necessary to override the swap effect
2218 * and to set it back after the flip.
2221 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2223 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2224 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2225 NULL, NULL, 0, NULL);
2227 swapchain->presentParms.SwapEffect = orig_swap;
2229 return WINED3D_OK;
2234 /* Blt from texture to rendertarget? */
2235 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2236 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2238 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2239 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2240 float glTexCoord[4];
2241 DWORD oldCKey;
2242 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2243 GLint alphafunc;
2244 GLclampf alpharef;
2245 GLint oldStencil;
2246 RECT SourceRectangle;
2247 GLint oldDraw;
2249 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2251 if(SrcRect) {
2252 SourceRectangle.left = SrcRect->left;
2253 SourceRectangle.right = SrcRect->right;
2254 SourceRectangle.top = SrcRect->top;
2255 SourceRectangle.bottom = SrcRect->bottom;
2256 } else {
2257 SourceRectangle.left = 0;
2258 SourceRectangle.right = Src->currentDesc.Width;
2259 SourceRectangle.top = 0;
2260 SourceRectangle.bottom = Src->currentDesc.Height;
2263 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2264 /* Fall back to software */
2265 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2266 SourceRectangle.left, SourceRectangle.top,
2267 SourceRectangle.right, SourceRectangle.bottom);
2268 return WINED3DERR_INVALIDCALL;
2271 /* Color keying: Check if we have to do a color keyed blt,
2272 * and if not check if a color key is activated.
2274 oldCKey = Src->CKeyFlags;
2275 if(!(Flags & DDBLT_KEYSRC) &&
2276 Src->CKeyFlags & DDSD_CKSRCBLT) {
2277 /* Ok, the surface has a color key, but we shall not use it -
2278 * Deactivate it for now and dirtify the surface to reload it
2280 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2281 Src->Flags |= SFLAG_DIRTY;
2284 /* Now load the surface */
2285 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2287 ENTER_GL();
2289 /* Save all the old stuff until we have a proper opengl state manager */
2290 oldLight = glIsEnabled(GL_LIGHTING);
2291 oldFog = glIsEnabled(GL_FOG);
2292 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2293 oldBlend = glIsEnabled(GL_BLEND);
2294 oldCull = glIsEnabled(GL_CULL_FACE);
2295 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2296 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2298 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2299 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2300 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2301 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2303 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2304 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2305 TRACE("Drawing to front buffer\n");
2306 glDrawBuffer(GL_FRONT);
2307 checkGLcall("glDrawBuffer GL_FRONT");
2310 /* Unbind the old texture */
2311 glBindTexture(GL_TEXTURE_2D, 0);
2313 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2314 /* We use texture unit 0 for blts */
2315 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2316 checkGLcall("glActiveTextureARB");
2317 } else {
2318 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2321 /* Disable some fancy graphics effects */
2322 glDisable(GL_LIGHTING);
2323 checkGLcall("glDisable GL_LIGHTING");
2324 glDisable(GL_DEPTH_TEST);
2325 checkGLcall("glDisable GL_DEPTH_TEST");
2326 glDisable(GL_FOG);
2327 checkGLcall("glDisable GL_FOG");
2328 glDisable(GL_BLEND);
2329 checkGLcall("glDisable GL_BLEND");
2330 glDisable(GL_CULL_FACE);
2331 checkGLcall("glDisable GL_CULL_FACE");
2332 glDisable(GL_STENCIL_TEST);
2333 checkGLcall("glDisable GL_STENCIL_TEST");
2335 /* Ok, we need 2d textures, but not 1D or 3D */
2336 glDisable(GL_TEXTURE_1D);
2337 checkGLcall("glDisable GL_TEXTURE_1D");
2338 glEnable(GL_TEXTURE_2D);
2339 checkGLcall("glEnable GL_TEXTURE_2D");
2340 glDisable(GL_TEXTURE_3D);
2341 checkGLcall("glDisable GL_TEXTURE_3D");
2343 /* Bind the texture */
2344 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2345 checkGLcall("glBindTexture");
2347 glEnable(GL_SCISSOR_TEST);
2349 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2351 /* No filtering for blts */
2352 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2353 GL_NEAREST);
2354 checkGLcall("glTexParameteri");
2355 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2356 GL_NEAREST);
2357 checkGLcall("glTexParameteri");
2358 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2359 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2360 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2361 checkGLcall("glTexEnvi");
2363 /* This is for color keying */
2364 if(Flags & DDBLT_KEYSRC) {
2365 glEnable(GL_ALPHA_TEST);
2366 checkGLcall("glEnable GL_ALPHA_TEST");
2367 glAlphaFunc(GL_NOTEQUAL, 0.0);
2368 checkGLcall("glAlphaFunc\n");
2369 } else {
2370 glDisable(GL_ALPHA_TEST);
2371 checkGLcall("glDisable GL_ALPHA_TEST");
2374 /* Draw a textured quad
2376 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2378 glBegin(GL_QUADS);
2380 glColor3d(1.0f, 1.0f, 1.0f);
2381 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2382 glVertex3f(rect.x1,
2383 rect.y1,
2384 0.0);
2386 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2387 glVertex3f(rect.x1, rect.y2, 0.0);
2389 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2390 glVertex3f(rect.x2,
2391 rect.y2,
2392 0.0);
2394 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2395 glVertex3f(rect.x2,
2396 rect.y1,
2397 0.0);
2398 glEnd();
2399 checkGLcall("glEnd");
2401 /* Unbind the texture */
2402 glBindTexture(GL_TEXTURE_2D, 0);
2403 checkGLcall("glEnable glBindTexture");
2405 /* Restore the old settings */
2406 if(oldLight) {
2407 glEnable(GL_LIGHTING);
2408 checkGLcall("glEnable GL_LIGHTING");
2410 if(oldFog) {
2411 glEnable(GL_FOG);
2412 checkGLcall("glEnable GL_FOG");
2414 if(oldDepth) {
2415 glEnable(GL_DEPTH_TEST);
2416 checkGLcall("glEnable GL_DEPTH_TEST");
2418 if(oldBlend) {
2419 glEnable(GL_BLEND);
2420 checkGLcall("glEnable GL_BLEND");
2422 if(oldCull) {
2423 glEnable(GL_CULL_FACE);
2424 checkGLcall("glEnable GL_CULL_FACE");
2426 if(oldStencil) {
2427 glEnable(GL_STENCIL_TEST);
2428 checkGLcall("glEnable GL_STENCIL_TEST");
2430 if(!oldAlpha) {
2431 glDisable(GL_ALPHA_TEST);
2432 checkGLcall("glDisable GL_ALPHA_TEST");
2433 } else {
2434 glEnable(GL_ALPHA_TEST);
2435 checkGLcall("glEnable GL_ALPHA_TEST");
2438 glAlphaFunc(alphafunc, alpharef);
2439 checkGLcall("glAlphaFunc\n");
2441 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2442 glDrawBuffer(oldDraw);
2445 /* Restore the color key */
2446 if(oldCKey != Src->CKeyFlags) {
2447 Src->CKeyFlags = oldCKey;
2448 Src->Flags |= SFLAG_DIRTY;
2451 LEAVE_GL();
2453 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2454 This->Flags |= SFLAG_GLDIRTY;
2456 return WINED3D_OK;
2460 /* Blt from rendertarget to texture? */
2461 if( (SrcSurface == swapchain->frontBuffer) ||
2462 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2463 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2464 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2465 UINT row;
2466 D3DRECT srect;
2467 float xrel, yrel;
2469 TRACE("Blt from rendertarget to texture\n");
2471 /* Call preload for the surface to make sure it isn't dirty */
2472 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2474 if(SrcRect) {
2475 srect.x1 = SrcRect->left;
2476 srect.y1 = SrcRect->top;
2477 srect.x2 = SrcRect->right;
2478 srect.y2 = SrcRect->bottom;
2479 } else {
2480 srect.x1 = 0;
2481 srect.y1 = 0;
2482 srect.x2 = Src->currentDesc.Width;
2483 srect.y2 = Src->currentDesc.Height;
2486 ENTER_GL();
2488 /* Bind the target texture */
2489 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2490 checkGLcall("glBindTexture");
2491 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2492 glReadBuffer(GL_BACK);
2493 } else {
2494 glReadBuffer(GL_FRONT);
2496 checkGLcall("glReadBuffer");
2498 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2499 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2501 /* I have to process this row by row to swap the image,
2502 * otherwise it would be upside down, so streching in y direction
2503 * doesn't cost extra time
2505 * However, streching in x direction can be avoided if not necessary
2507 for(row = rect.y1; row < rect.y2; row++) {
2508 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2509 /* Well, that stuff works, but it's very slow.
2510 * find a better way instead
2512 UINT col;
2513 for(col = rect.x1; col < rect.x2; col++) {
2514 glCopyTexSubImage2D(GL_TEXTURE_2D,
2515 0, /* level */
2516 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2517 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2518 1, 1);
2520 } else {
2521 glCopyTexSubImage2D(GL_TEXTURE_2D,
2522 0, /* level */
2523 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2524 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2525 rect.x2, 1);
2529 vcheckGLcall("glCopyTexSubImage2D");
2530 LEAVE_GL();
2532 if(!(This->Flags & SFLAG_DONOTFREE)) {
2533 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2534 This->resource.allocatedMemory = NULL;
2535 } else {
2536 This->Flags |= SFLAG_GLDIRTY;
2539 return WINED3D_OK;
2544 if (Flags & DDBLT_COLORFILL) {
2545 /* This is easy to handle for the D3D Device... */
2546 DWORD color;
2547 IWineD3DSwapChainImpl *implSwapChain;
2549 TRACE("Colorfill\n");
2551 /* The color as given in the Blt function is in the format of the frame-buffer...
2552 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2554 if (This->resource.format == WINED3DFMT_P8) {
2555 if (This->palette) {
2556 color = ((0xFF000000) |
2557 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2558 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2559 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2560 } else {
2561 color = 0xFF000000;
2564 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2565 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2566 color = 0xFFFFFFFF;
2567 } else {
2568 color = ((0xFF000000) |
2569 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2570 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2571 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2574 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2575 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2576 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2578 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2579 color = DDBltFx->u5.dwFillColor;
2581 else {
2582 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2583 return WINED3DERR_INVALIDCALL;
2586 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2587 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2588 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2589 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2590 glDrawBuffer(GL_BACK);
2591 checkGLcall("glDrawBuffer(GL_BACK)");
2593 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2594 glDrawBuffer(GL_FRONT);
2595 checkGLcall("glDrawBuffer(GL_FRONT)");
2597 else {
2598 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2599 return WINED3DERR_INVALIDCALL;
2602 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2604 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2605 1 /* Number of rectangles */,
2606 &rect,
2607 D3DCLEAR_TARGET,
2608 color,
2609 0.0 /* Z */,
2610 0 /* Stencil */);
2612 /* Restore the original draw buffer */
2613 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2614 glDrawBuffer(GL_BACK);
2615 vcheckGLcall("glDrawBuffer");
2618 return WINED3D_OK;
2621 /* Default: Fall back to the generic blt */
2622 return WINED3DERR_INVALIDCALL;
2625 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2626 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2627 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2628 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2629 TRACE("(%p): Usage is %08lx\n", This, This->resource.usage);
2631 /* Special cases for RenderTargets */
2632 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2633 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2634 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2637 /* For the rest call the X11 surface implementation.
2638 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2639 * other Blts are rather rare
2641 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2644 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2645 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2646 TRACE("(%p)->(%lx)\n", This, Flags);
2648 switch (Flags)
2650 case DDGBS_CANBLT:
2651 case DDGBS_ISBLTDONE:
2652 return DD_OK;
2654 default:
2655 return DDERR_INVALIDPARAMS;
2659 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2660 /* XXX: DDERR_INVALIDSURFACETYPE */
2662 TRACE("(%p)->(%08lx)\n",iface,Flags);
2663 switch (Flags) {
2664 case DDGFS_CANFLIP:
2665 case DDGFS_ISFLIPDONE:
2666 return DD_OK;
2668 default:
2669 return DDERR_INVALIDPARAMS;
2673 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2674 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2675 TRACE("(%p)\n", This);
2677 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2680 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2681 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2682 TRACE("(%p)\n", This);
2684 /* So far we don't lose anything :) */
2685 This->Flags &= ~SFLAG_LOST;
2686 return WINED3D_OK;
2689 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2690 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2691 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2692 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2694 /* Special cases for RenderTargets */
2695 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2696 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2698 RECT SrcRect, DstRect;
2700 if(rsrc) {
2701 SrcRect.left = rsrc->left;
2702 SrcRect.top= rsrc->top;
2703 SrcRect.bottom = rsrc->bottom;
2704 SrcRect.right = rsrc->right;
2705 } else {
2706 SrcRect.left = 0;
2707 SrcRect.top = 0;
2708 SrcRect.right = srcImpl->currentDesc.Width;
2709 SrcRect.bottom = srcImpl->currentDesc.Height;
2712 DstRect.left = dstx;
2713 DstRect.top=dsty;
2714 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2715 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2717 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, 0, NULL) == WINED3D_OK) return WINED3D_OK;
2721 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2724 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2725 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2726 TRACE("(%p)->(%p)\n", This, Pal);
2728 *Pal = (IWineD3DPalette *) This->palette;
2729 return DD_OK;
2732 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2733 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2734 RGBQUAD col[256];
2735 IWineD3DPaletteImpl *pal = This->palette;
2736 unsigned int n;
2737 TRACE("(%p)\n", This);
2739 if(This->resource.format == WINED3DFMT_P8 ||
2740 This->resource.format == WINED3DFMT_A8P8)
2742 TRACE("Dirtifying surface\n");
2743 This->Flags |= SFLAG_DIRTY;
2746 if(This->Flags & SFLAG_DIBSECTION) {
2747 TRACE("(%p): Updating the hdc's palette\n", This);
2748 for (n=0; n<256; n++) {
2749 if(pal) {
2750 col[n].rgbRed = pal->palents[n].peRed;
2751 col[n].rgbGreen = pal->palents[n].peGreen;
2752 col[n].rgbBlue = pal->palents[n].peBlue;
2753 } else {
2754 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2755 /* Use the default device palette */
2756 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2757 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2758 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2760 col[n].rgbReserved = 0;
2762 SetDIBColorTable(This->hDC, 0, 256, col);
2765 return WINED3D_OK;
2768 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2769 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2770 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2771 TRACE("(%p)->(%p)\n", This, Pal);
2773 if(This->palette != NULL)
2774 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2775 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2777 if(PalImpl != NULL) {
2778 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2779 /* Set the device's main palette if the palette
2780 * wasn't a primary palette before
2782 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2783 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2784 unsigned int i;
2786 for(i=0; i < 256; i++) {
2787 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2791 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2794 This->palette = PalImpl;
2796 return IWineD3DSurface_RealizePalette(iface);
2799 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2800 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2801 BOOL dirtify = FALSE;
2802 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
2804 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2805 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
2806 return DDERR_INVALIDPARAMS;
2809 /* Dirtify the surface, but only if a key was changed */
2810 if(CKey) {
2811 switch (Flags & ~DDCKEY_COLORSPACE) {
2812 case DDCKEY_DESTBLT:
2813 if(!(This->CKeyFlags & DDSD_CKDESTBLT)) {
2814 dirtify = TRUE;
2815 } else {
2816 dirtify = memcmp(&This->DestBltCKey, CKey, sizeof(*CKey) ) != 0;
2818 This->DestBltCKey = *CKey;
2819 This->CKeyFlags |= DDSD_CKDESTBLT;
2820 break;
2822 case DDCKEY_DESTOVERLAY:
2823 if(!(This->CKeyFlags & DDSD_CKDESTOVERLAY)) {
2824 dirtify = TRUE;
2825 } else {
2826 dirtify = memcmp(&This->DestOverlayCKey, CKey, sizeof(*CKey)) != 0;
2828 This->DestOverlayCKey = *CKey;
2829 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2830 break;
2832 case DDCKEY_SRCOVERLAY:
2833 if(!(This->CKeyFlags & DDSD_CKSRCOVERLAY)) {
2834 dirtify = TRUE;
2835 } else {
2836 dirtify = memcmp(&This->SrcOverlayCKey, CKey, sizeof(*CKey)) != 0;
2838 This->SrcOverlayCKey = *CKey;
2839 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2840 break;
2842 case DDCKEY_SRCBLT:
2843 if(!(This->CKeyFlags & DDSD_CKSRCBLT)) {
2844 dirtify = TRUE;
2845 } else {
2846 dirtify = memcmp(&This->SrcBltCKey, CKey, sizeof(*CKey)) != 0;
2848 This->SrcBltCKey = *CKey;
2849 This->CKeyFlags |= DDSD_CKSRCBLT;
2850 break;
2853 else {
2854 switch (Flags & ~DDCKEY_COLORSPACE) {
2855 case DDCKEY_DESTBLT:
2856 dirtify = This->CKeyFlags & DDSD_CKDESTBLT;
2857 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2858 break;
2860 case DDCKEY_DESTOVERLAY:
2861 dirtify = This->CKeyFlags & DDSD_CKDESTOVERLAY;
2862 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2863 break;
2865 case DDCKEY_SRCOVERLAY:
2866 dirtify = This->CKeyFlags & DDSD_CKSRCOVERLAY;
2867 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2868 break;
2870 case DDCKEY_SRCBLT:
2871 dirtify = This->CKeyFlags & DDSD_CKSRCBLT;
2872 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2873 break;
2877 if(dirtify) {
2878 TRACE("Color key changed, dirtifying surface\n");
2879 This->Flags |= SFLAG_DIRTY;
2882 return WINED3D_OK;
2885 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2886 /** Check against the maximum texture sizes supported by the video card **/
2887 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2889 TRACE("%p\n", This);
2890 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2891 /* one of three options
2892 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)
2893 2: Set the texture to the maxium size (bad idea)
2894 3: WARN and return WINED3DERR_NOTAVAILABLE;
2895 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.
2897 WARN("(%p) Creating an oversized surface\n", This);
2898 This->Flags |= SFLAG_OVERSIZE;
2900 /* This will be initialized on the first blt */
2901 This->glRect.left = 0;
2902 This->glRect.top = 0;
2903 This->glRect.right = 0;
2904 This->glRect.bottom = 0;
2905 } else {
2906 /* No oversize, gl rect is the full texture size */
2907 This->Flags &= ~SFLAG_OVERSIZE;
2908 This->glRect.left = 0;
2909 This->glRect.top = 0;
2910 This->glRect.right = This->pow2Width;
2911 This->glRect.bottom = This->pow2Height;
2914 return WINED3D_OK;
2917 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
2918 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2919 DWORD ret;
2920 TRACE("(%p)\n", This);
2922 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
2923 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
2924 ie pitch = (width/4) * bytes per block */
2925 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
2926 ret = (This->currentDesc.Width >> 2) << 3;
2927 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
2928 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
2929 ret = (This->currentDesc.Width >> 2) << 4;
2930 else {
2931 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2932 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
2933 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
2934 } else {
2935 ret = This->bytesPerPixel * This->pow2Width;
2938 TRACE("(%p) Returning %ld\n", This, ret);
2939 return ret;
2942 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
2944 /* IUnknown */
2945 IWineD3DSurfaceImpl_QueryInterface,
2946 IWineD3DSurfaceImpl_AddRef,
2947 IWineD3DSurfaceImpl_Release,
2948 /* IWineD3DResource */
2949 IWineD3DSurfaceImpl_GetParent,
2950 IWineD3DSurfaceImpl_GetDevice,
2951 IWineD3DSurfaceImpl_SetPrivateData,
2952 IWineD3DSurfaceImpl_GetPrivateData,
2953 IWineD3DSurfaceImpl_FreePrivateData,
2954 IWineD3DSurfaceImpl_SetPriority,
2955 IWineD3DSurfaceImpl_GetPriority,
2956 IWineD3DSurfaceImpl_PreLoad,
2957 IWineD3DSurfaceImpl_GetType,
2958 /* IWineD3DSurface */
2959 IWineD3DSurfaceImpl_GetContainerParent,
2960 IWineD3DSurfaceImpl_GetContainer,
2961 IWineD3DSurfaceImpl_GetDesc,
2962 IWineD3DSurfaceImpl_LockRect,
2963 IWineD3DSurfaceImpl_UnlockRect,
2964 IWineD3DSurfaceImpl_GetDC,
2965 IWineD3DSurfaceImpl_ReleaseDC,
2966 IWineD3DSurfaceImpl_Flip,
2967 IWineD3DSurfaceImpl_Blt,
2968 IWineD3DSurfaceImpl_GetBltStatus,
2969 IWineD3DSurfaceImpl_GetFlipStatus,
2970 IWineD3DSurfaceImpl_IsLost,
2971 IWineD3DSurfaceImpl_Restore,
2972 IWineD3DSurfaceImpl_BltFast,
2973 IWineD3DSurfaceImpl_GetPalette,
2974 IWineD3DSurfaceImpl_SetPalette,
2975 IWineD3DSurfaceImpl_RealizePalette,
2976 IWineD3DSurfaceImpl_SetColorKey,
2977 IWineD3DSurfaceImpl_GetPitch,
2978 /* Internal use: */
2979 IWineD3DSurfaceImpl_CleanDirtyRect,
2980 IWineD3DSurfaceImpl_AddDirtyRect,
2981 IWineD3DSurfaceImpl_LoadTexture,
2982 IWineD3DSurfaceImpl_SaveSnapshot,
2983 IWineD3DSurfaceImpl_SetContainer,
2984 IWineD3DSurfaceImpl_SetPBufferState,
2985 IWineD3DSurfaceImpl_SetGlTextureDesc,
2986 IWineD3DSurfaceImpl_GetGlDesc,
2987 IWineD3DSurfaceImpl_GetData,
2988 IWineD3DSurfaceImpl_SetFormat,
2989 IWineD3DSurfaceImpl_PrivateSetup