msi: Add the total and free disk space to the VolumeCostList control.
[wine/testsucceed.git] / dlls / wined3d / surface.c
blob908211e07ae683fe2cdda37b6237bfb66b0b8da0
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 static void surface_download_data(IWineD3DSurfaceImpl *This) {
53 if (This->resource.format == WINED3DFMT_DXT1 ||
54 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
55 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
56 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* We can assume this as the texture would not have been created otherwise */
57 FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
58 } else {
59 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
60 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
62 ENTER_GL();
64 GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory));
65 checkGLcall("glGetCompressedTexImageARB()");
67 LEAVE_GL();
69 } else {
70 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
71 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
73 ENTER_GL();
75 glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
76 This->glDescription.glType, This->resource.allocatedMemory);
77 checkGLcall("glGetTexImage()");
79 LEAVE_GL();
81 if (wined3d_settings.nonpower2_mode == NP2_REPACK) {
83 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
84 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
85 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
87 * We're doing this...
89 * instead of boxing the texture :
90 * |<-texture width ->| -->pow2width| /\
91 * |111111111111111111| | |
92 * |222 Texture 222222| boxed empty | texture height
93 * |3333 Data 33333333| | |
94 * |444444444444444444| | \/
95 * ----------------------------------- |
96 * | boxed empty | boxed empty | pow2height
97 * | | | \/
98 * -----------------------------------
101 * we're repacking the data to the expected texture width
103 * |<-texture width ->| -->pow2width| /\
104 * |111111111111111111222222222222222| |
105 * |222333333333333333333444444444444| texture height
106 * |444444 | |
107 * | | \/
108 * | | |
109 * | empty | pow2height
110 * | | \/
111 * -----------------------------------
113 * == is the same as
115 * |<-texture width ->| /\
116 * |111111111111111111|
117 * |222222222222222222|texture height
118 * |333333333333333333|
119 * |444444444444444444| \/
120 * --------------------
122 * this also means that any references to allocatedMemory should work with the data as if were a
123 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
125 * internally the texture is still stored in a boxed format so any references to textureName will
126 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
129 if (This->Flags & SFLAG_NONPOW2) {
130 LPBYTE src_data, dst_data;
131 int src_pitch = This->bytesPerPixel * This->pow2Width;
132 int dst_pitch = This->bytesPerPixel * This->currentDesc.Width;
133 int y;
135 src_data = dst_data = This->resource.allocatedMemory;
136 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
137 for (y = 1 ; y < This->currentDesc.Height; y++) {
138 /* skip the first row */
139 src_data += src_pitch;
140 dst_data += dst_pitch;
141 memcpy(dst_data, src_data, dst_pitch);
148 static void surface_upload_data(IWineD3DSurfaceImpl *This, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data) {
149 if (This->resource.format == WINED3DFMT_DXT1 ||
150 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
151 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
152 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
153 FIXME("Using DXT1/3/5 without advertized support\n");
154 } else {
155 TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data);
156 ENTER_GL();
157 GL_EXTCALL(glCompressedTexSubImage2DARB(This->glDescription.target, This->glDescription.level, 0, 0, width, height,
158 This->glDescription.glFormatInternal, This->resource.size, data));
159 checkGLcall("glCompressedTexSubImage2D");
160 LEAVE_GL();
162 } else {
163 TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This, width, height, data);
164 ENTER_GL();
165 glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data);
166 checkGLcall("glTexSubImage2D");
167 LEAVE_GL();
171 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) {
172 TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n", This,
173 This->glDescription.target, This->glDescription.level, debug_d3dformat(This->resource.format), internal, width, height, format, type);
175 ENTER_GL();
177 glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, NULL);
178 checkGLcall("glTexImage2D");
180 LEAVE_GL();
183 /* *******************************************
184 IWineD3DSurface IUnknown parts follow
185 ******************************************* */
186 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
188 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
189 /* Warn ,but be nice about things */
190 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
191 if (riid == NULL) {
192 ERR("Probably FIXME: Calling query interface with NULL riid\n");
194 if (IsEqualGUID(riid, &IID_IUnknown)
195 || IsEqualGUID(riid, &IID_IWineD3DBase)
196 || IsEqualGUID(riid, &IID_IWineD3DResource)
197 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
198 IUnknown_AddRef((IUnknown*)iface);
199 *ppobj = This;
200 return S_OK;
202 *ppobj = NULL;
203 return E_NOINTERFACE;
206 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
207 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
208 ULONG ref = InterlockedIncrement(&This->resource.ref);
209 TRACE("(%p) : AddRef increasing from %ld\n", This,ref - 1);
210 return ref;
213 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
214 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
215 ULONG ref = InterlockedDecrement(&This->resource.ref);
216 TRACE("(%p) : Releasing from %ld\n", This, ref + 1);
217 if (ref == 0) {
218 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
219 TRACE("(%p) : cleaning up\n", This);
220 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
221 ENTER_GL();
222 TRACE("Deleting texture %d\n", This->glDescription.textureName);
223 glDeleteTextures(1, &This->glDescription.textureName);
224 LEAVE_GL();
227 if(This->Flags & SFLAG_DIBSECTION) {
228 /* Release the DC */
229 SelectObject(This->hDC, This->dib.holdbitmap);
230 DeleteDC(This->hDC);
231 /* Release the DIB section */
232 DeleteObject(This->dib.DIBsection);
233 This->dib.bitmap_data = NULL;
234 This->resource.allocatedMemory = NULL;
236 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
238 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
239 if(iface == device->ddraw_primary)
240 device->ddraw_primary = NULL;
242 TRACE("(%p) Released\n", This);
243 HeapFree(GetProcessHeap(), 0, This);
246 return ref;
249 /* ****************************************************
250 IWineD3DSurface IWineD3DResource parts follow
251 **************************************************** */
252 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
253 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
256 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
257 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
260 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
261 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
264 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
265 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
268 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
269 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
272 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
273 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
276 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
277 /* TODO: re-write the way textures and managed,
278 * use a 'opengl context manager' to manage RenderTarget surfaces
279 ** *********************************************************/
281 /* TODO: check for locks */
282 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
283 IWineD3DBaseTexture *baseTexture = NULL;
284 TRACE("(%p)Checking to see if the container is a base texture\n", This);
285 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
286 TRACE("Passing to conatiner\n");
287 IWineD3DBaseTexture_PreLoad(baseTexture);
288 IWineD3DBaseTexture_Release(baseTexture);
289 } else {
290 TRACE("(%p) : About to load surface\n", This);
291 ENTER_GL();
292 #if 0 /* TODO: context manager support */
293 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
294 #endif
295 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
296 if (!This->glDescription.level) {
297 if (!This->glDescription.textureName) {
298 glGenTextures(1, &This->glDescription.textureName);
299 checkGLcall("glGenTextures");
300 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
302 glBindTexture(This->glDescription.target, This->glDescription.textureName);
303 checkGLcall("glBindTexture");
304 IWineD3DSurface_LoadTexture(iface);
305 /* This is where we should be reducing the amount of GLMemoryUsed */
306 } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
307 /* assume this is a coding error not a real error for now */
308 FIXME("Mipmap surface has a glTexture bound to it!\n");
310 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
311 /* Tell opengl to try and keep this texture in video ram (well mostly) */
312 GLclampf tmp;
313 tmp = 0.9f;
314 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
316 /* TODO: disable texture support, if it wastn't enabled when we entered. */
317 #if 0 /* TODO: context manager support */
318 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
319 /* we don't care when the state is disabled(if atall) */);
320 #endif
321 LEAVE_GL();
323 return;
326 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
327 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
328 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
331 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
332 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
333 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
336 /* ******************************************************
337 IWineD3DSurface IWineD3DSurface parts follow
338 ****************************************************** */
340 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainerParent(IWineD3DSurface* iface, IUnknown **ppContainerParent) {
341 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
343 TRACE("(%p) : ppContainerParent %p)\n", This, ppContainerParent);
345 if (!ppContainerParent) {
346 ERR("(%p) : Called without a valid ppContainerParent.\n", This);
349 if (This->container) {
350 IWineD3DBase_GetParent(This->container, ppContainerParent);
351 if (!ppContainerParent) {
352 /* WineD3D objects should always have a parent */
353 ERR("(%p) : GetParent returned NULL\n", This);
355 IUnknown_Release(*ppContainerParent); /* GetParent adds a reference; we want just the pointer */
356 } else {
357 *ppContainerParent = NULL;
360 return WINED3D_OK;
363 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
364 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
365 IWineD3DBase *container = 0;
367 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
369 if (!ppContainer) {
370 ERR("Called without a valid ppContainer.\n");
373 /** From MSDN:
374 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
375 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
376 * GetContainer will return the Direct3D device used to create the surface.
378 if (This->container) {
379 container = This->container;
380 } else {
381 container = (IWineD3DBase *)This->resource.wineD3DDevice;
384 TRACE("Relaying to QueryInterface\n");
385 return IUnknown_QueryInterface(container, riid, ppContainer);
388 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
389 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
391 TRACE("(%p) : copying into %p\n", This, pDesc);
392 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
393 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
394 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
395 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
396 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
397 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
398 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
399 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
400 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
401 return WINED3D_OK;
404 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
405 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
406 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
407 if (This->glDescription.textureName == 0 && textureName != 0) {
408 This->Flags |= SFLAG_DIRTY;
409 IWineD3DSurface_AddDirtyRect(iface, NULL);
411 This->glDescription.textureName = textureName;
412 This->glDescription.target = target;
415 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
416 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
417 TRACE("(%p) : returning %p\n", This, &This->glDescription);
418 *glDescription = &This->glDescription;
421 /* TODO: think about moving this down to resource? */
422 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
423 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
424 /* 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 */
425 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
426 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
428 return (CONST void*)(This->resource.allocatedMemory);
431 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
432 long j;
433 void *mem;
434 GLint fmt;
435 GLint type;
437 switch(This->resource.format)
439 case WINED3DFMT_P8:
441 /* GL can't return palettized data, so read ARGB pixels into a
442 * separate block of memory and convert them into palettized format
443 * in software. Slow, but if the app means to use palettized render
444 * targets and locks it...
446 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
447 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
448 * for the color channels when palettizing the colors.
450 fmt = GL_RGB;
451 type = GL_UNSIGNED_BYTE;
452 pitch *= 3;
453 mem = HeapAlloc(GetProcessHeap(), 0, (rect->bottom - rect->top) * pitch);
454 if(!mem) {
455 ERR("Out of memory\n");
456 return;
459 break;
461 default:
462 mem = dest;
463 fmt = This->glDescription.glFormat;
464 type = This->glDescription.glType;
467 if (rect->left == 0 &&
468 rect->right == This->currentDesc.Width ) {
469 BYTE *row, *top, *bottom;
470 int i;
472 glReadPixels(0, rect->top,
473 This->currentDesc.Width,
474 rect->bottom - rect->top,
475 fmt,
476 type,
477 mem);
479 /* glReadPixels returns the image upside down, and there is no way to prevent this.
480 Flip the lines in software */
481 row = HeapAlloc(GetProcessHeap(), 0, pitch);
482 if(!row) {
483 ERR("Out of memory\n");
484 return;
486 top = mem;
487 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
488 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
489 memcpy(row, top, pitch);
490 memcpy(top, bottom, pitch);
491 memcpy(bottom, row, pitch);
492 top += pitch;
493 bottom -= pitch;
495 HeapFree(GetProcessHeap(), 0, row);
497 if(This->lockedRect.top == 0 && This->lockedRect.bottom == This->currentDesc.Height) {
498 This->Flags &= ~SFLAG_GLDIRTY;
500 } else {
501 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
502 glReadPixels(rect->left,
503 rect->bottom - j - 1,
504 rect->right - rect->left,
506 fmt,
507 type,
508 (char *)mem + (pitch * (j-rect->top)));
512 vcheckGLcall("glReadPixels");
514 if(This->resource.format == WINED3DFMT_P8) {
515 PALETTEENTRY *pal;
516 DWORD width = pitch / 3;
517 int x, y, c;
518 if(This->palette) {
519 pal = This->palette->palents;
520 } else {
521 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
524 for(y = rect->top; y < rect->bottom; y++) {
525 for(x = rect->left; x < rect->right; x++) {
526 /* start lines pixels */
527 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
528 BYTE *green = blue + 1;
529 BYTE *red = green + 1;
531 for(c = 0; c < 256; c++) {
532 if(*red == pal[c].peRed &&
533 *green == pal[c].peGreen &&
534 *blue == pal[c].peBlue)
536 *((BYTE *) dest + y * width + x) = c;
537 break;
542 HeapFree(GetProcessHeap(), 0, mem);
546 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
547 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
548 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
549 IWineD3DSwapChainImpl *swapchain = NULL;
550 static UINT messages = 0; /* holds flags to disable fixme messages */
551 BOOL backbuf = FALSE;
553 /* fixme: should we really lock as such? */
554 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
555 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
556 FIXME("Warning: Surface is in texture memory or pbuffer\n");
557 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
560 if (!(This->Flags & SFLAG_LOCKABLE)) {
561 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
562 texture regions, and since the destination is an unlockable region we need
563 to tolerate this */
564 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
565 /*return WINED3DERR_INVALIDCALL; */
568 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
569 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
571 if (swapchain != NULL || iface == myDevice->renderTarget || iface == myDevice->depthStencilBuffer) {
572 if(swapchain != NULL) {
573 int i;
574 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
575 if(iface == swapchain->backBuffer[i]) {
576 backbuf = TRUE;
577 break;
581 if (backbuf) {
582 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
583 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
584 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
585 } else if (iface == myDevice->renderTarget) {
586 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
587 } else if (iface == myDevice->depthStencilBuffer) {
588 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
591 if (NULL != swapchain) {
592 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
594 swapchain = NULL;
596 } else {
597 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
600 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
602 if (NULL == pRect) {
603 pLockedRect->pBits = This->resource.allocatedMemory;
604 This->lockedRect.left = 0;
605 This->lockedRect.top = 0;
606 This->lockedRect.right = This->currentDesc.Width;
607 This->lockedRect.bottom = This->currentDesc.Height;
608 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);
609 } else {
610 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
612 if ((pRect->top < 0) ||
613 (pRect->left < 0) ||
614 (pRect->left >= pRect->right) ||
615 (pRect->top >= pRect->bottom) ||
616 (pRect->right > This->currentDesc.Width) ||
617 (pRect->bottom > This->currentDesc.Height))
619 WARN(" Invalid values in pRect !!!\n");
620 return D3DERR_INVALIDCALL;
623 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
624 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
625 } else {
626 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
628 This->lockedRect.left = pRect->left;
629 This->lockedRect.top = pRect->top;
630 This->lockedRect.right = pRect->right;
631 This->lockedRect.bottom = pRect->bottom;
634 if (This->Flags & SFLAG_NONPOW2) {
635 TRACE("Locking non-power 2 texture\n");
638 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
639 /* classic surface TODO: non 2d surfaces?
640 These resources may be POOL_SYSTEMMEM, so they must not access the device */
641 TRACE("locking an ordinarary surface\n");
642 /* Check to see if memory has already been allocated from the surface*/
643 if ((NULL == This->resource.allocatedMemory) ||
644 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
645 /* Non-system memory surfaces */
647 This->Flags &= ~SFLAG_GLDIRTY;
649 /*Surface has no memory currently allocated to it!*/
650 TRACE("(%p) Locking rect\n" , This);
651 if(!This->resource.allocatedMemory) {
652 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
654 if (0 != This->glDescription.textureName) {
655 /* Now I have to copy thing bits back */
656 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
657 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
659 /* Make sure that the texture is loaded */
660 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
662 surface_download_data(This);
664 } else { /* Nothing to do */
665 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
668 if (NULL == pRect) {
669 pLockedRect->pBits = This->resource.allocatedMemory;
670 } else{
671 if (This->resource.format == D3DFMT_DXT1) { /* DXT1 is half byte per pixel */
672 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
673 } else {
674 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
678 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
679 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
680 GLint prev_store;
681 GLint prev_read;
682 BOOL notInContext = FALSE;
683 IWineD3DSwapChainImpl *targetSwapChain = NULL;
686 ENTER_GL();
689 * for render->surface copy begin to begin of allocatedMemory
690 * unlock can be more easy
693 TRACE("locking a render target\n");
695 if (This->resource.allocatedMemory == NULL)
696 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
698 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
699 pLockedRect->pBits = This->resource.allocatedMemory;
701 glFlush();
702 vcheckGLcall("glFlush");
703 glGetIntegerv(GL_READ_BUFFER, &prev_read);
704 vcheckGLcall("glIntegerv");
705 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
706 vcheckGLcall("glIntegerv");
708 /* Here's what we have to do:
709 See if the swapchain has the same context as the renderTarget or the surface is the render target.
710 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
711 and use the front back buffer as required.
712 if not, we need to switch contexts and then switchback at the end.
714 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
715 IWineD3DSurface_GetContainer(myDevice->renderTarget, &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
717 /* 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! */
718 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->renderTarget) {
719 if (swapchain && iface == swapchain->frontBuffer) {
720 TRACE("locking front\n");
721 glReadBuffer(GL_FRONT);
723 else if (iface == myDevice->renderTarget || backbuf) {
724 TRACE("locking back buffer\n");
725 glReadBuffer(GL_BACK);
726 } else if (iface == myDevice->depthStencilBuffer) {
727 FIXME("Stencil Buffer lock unsupported for now\n");
728 } else {
729 FIXME("(%p) Shouldn't have got here!\n", This);
730 glReadBuffer(GL_BACK);
732 } else if (swapchain != NULL) {
733 IWineD3DSwapChainImpl *implSwapChain;
734 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
735 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
736 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
737 if (backbuf) {
738 glReadBuffer(GL_BACK);
739 } else if (iface == swapchain->frontBuffer) {
740 glReadBuffer(GL_FRONT);
741 } else if (iface == myDevice->depthStencilBuffer) {
742 FIXME("Stencil Buffer lock unsupported for now\n");
743 } else {
744 FIXME("Should have got here!\n");
745 glReadBuffer(GL_BACK);
747 } else {
748 /* We need to switch contexts to be able to read the buffer!!! */
749 FIXME("The buffer requested isn't in the current openGL context\n");
750 notInContext = TRUE;
751 /* TODO: check the contexts, to see if were shared with the current context */
753 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
755 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
756 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
758 /** the depth stencil in openGL has a format of GL_FLOAT
759 * which should be good for WINED3DFMT_D16_LOCKABLE
760 * and WINED3DFMT_D16
761 * it is unclear what format the stencil buffer is in except.
762 * 'Each index is converted to fixed point...
763 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
764 * mappings in the table GL_PIXEL_MAP_S_TO_S.
765 * glReadPixels(This->lockedRect.left,
766 * This->lockedRect.bottom - j - 1,
767 * This->lockedRect.right - This->lockedRect.left,
768 * 1,
769 * GL_DEPTH_COMPONENT,
770 * type,
771 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
772 *****************************************/
773 if (!notInContext) { /* Only read the buffer if it's in the current context */
774 switch(wined3d_settings.rendertargetlock_mode) {
775 case RTL_AUTO:
776 case RTL_READDRAW:
777 case RTL_READTEX:
778 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
779 break;
781 case RTL_TEXDRAW:
782 case RTL_TEXTEX:
783 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
784 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
785 break;
787 case RTL_DISABLE:
789 static BOOL warned = FALSE;
790 if(!warned) {
791 ERR("Application tries to lock the render target, but render target locking is disabled\n");
792 warned = TRUE;
795 break;
798 TRACE("Resetting buffer\n");
800 glReadBuffer(prev_read);
801 vcheckGLcall("glReadBuffer");
803 LEAVE_GL();
805 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
807 if (!messages & 1) {
808 FIXME("TODO stencil depth surface locking surf%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
811 glReadPixels(This->lockedRect.left,
812 This->lockedRect.bottom - j - 1,
813 This->lockedRect.right - This->lockedRect.left,
815 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
819 messages |= 1;
821 } else {
822 FIXME("unsupported locking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
825 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
826 /* Don't dirtify */
827 } else {
828 IWineD3DBaseTexture *pBaseTexture;
830 * Dirtify on lock
831 * as seen in msdn docs
833 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
835 /** Dirtify Container if needed */
836 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
837 TRACE("Making container dirty\n");
838 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
839 IWineD3DBaseTexture_Release(pBaseTexture);
840 } else {
841 TRACE("Surface is standalone, no need to dirty the container\n");
845 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
847 This->Flags |= SFLAG_LOCKED;
848 return WINED3D_OK;
851 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
852 GLint prev_store;
853 GLint prev_rasterpos[4];
854 GLint skipBytes = 0;
855 BOOL storechanged = FALSE;
856 GLint fmt, type;
857 void *mem;
859 glDisable(GL_TEXTURE_2D);
860 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
861 glDisable(GL_TEXTURE_1D);
862 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
864 glFlush();
865 vcheckGLcall("glFlush");
866 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
867 vcheckGLcall("glIntegerv");
868 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
869 vcheckGLcall("glIntegerv");
870 glPixelZoom(1.0, -1.0);
871 vcheckGLcall("glPixelZoom");
873 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
874 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
875 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
877 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
878 vcheckGLcall("glRasterPos2f");
880 /* Some drivers(radeon dri, others?) don't like exceptions during
881 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
882 * after ReleaseDC. Reading it will cause an exception, which x11drv will
883 * catch to put the dib section in InSync mode, which leads to a crash
884 * and a blocked x server on my radeon card.
886 * The following lines read the dib section so it is put in inSync mode
887 * before glDrawPixels is called and the crash is prevented. There won't
888 * be any interfering gdi accesses, because UnlockRect is called from
889 * ReleaseDC, and the app won't use the dc any more afterwards.
891 if(This->Flags & SFLAG_DIBSECTION) {
892 volatile BYTE read;
893 read = This->resource.allocatedMemory[0];
896 switch (This->resource.format) {
897 /* No special care needed */
898 case WINED3DFMT_A4R4G4B4:
899 case WINED3DFMT_R5G6B5:
900 case WINED3DFMT_A1R5G5B5:
901 case WINED3DFMT_R8G8B8:
902 type = This->glDescription.glType;
903 fmt = This->glDescription.glFormat;
904 mem = This->resource.allocatedMemory;
905 break;
907 case WINED3DFMT_X4R4G4B4:
909 int size;
910 unsigned short *data;
911 data = (unsigned short *)This->resource.allocatedMemory;
912 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
913 while(size > 0) {
914 *data |= 0xF000;
915 data++;
916 size--;
918 type = This->glDescription.glType;
919 fmt = This->glDescription.glFormat;
920 mem = This->resource.allocatedMemory;
922 break;
924 case WINED3DFMT_X1R5G5B5:
926 int size;
927 unsigned short *data;
928 data = (unsigned short *)This->resource.allocatedMemory;
929 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
930 while(size > 0) {
931 *data |= 0x8000;
932 data++;
933 size--;
935 type = This->glDescription.glType;
936 fmt = This->glDescription.glFormat;
937 mem = This->resource.allocatedMemory;
939 break;
941 case WINED3DFMT_X8R8G8B8:
943 /* make sure the X byte is set to alpha on, since it
944 could be any random value. This fixes the intro movie in Pirates! */
945 int size;
946 unsigned int *data;
947 data = (unsigned int *)This->resource.allocatedMemory;
948 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
949 while(size > 0) {
950 *data |= 0xFF000000;
951 data++;
952 size--;
955 /* Fall through */
957 case WINED3DFMT_A8R8G8B8:
959 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
960 vcheckGLcall("glPixelStorei");
961 storechanged = TRUE;
962 type = This->glDescription.glType;
963 fmt = This->glDescription.glFormat;
964 mem = This->resource.allocatedMemory;
966 break;
968 case WINED3DFMT_A2R10G10B10:
970 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
971 vcheckGLcall("glPixelStorei");
972 storechanged = TRUE;
973 type = This->glDescription.glType;
974 fmt = This->glDescription.glFormat;
975 mem = This->resource.allocatedMemory;
977 break;
979 case WINED3DFMT_P8:
981 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
982 int height = This->glRect.bottom - This->glRect.top;
983 type = GL_UNSIGNED_BYTE;
984 fmt = GL_RGBA;
986 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
987 if(!mem) {
988 ERR("Out of memory\n");
989 return;
991 d3dfmt_convert_surface(This->resource.allocatedMemory,
992 mem,
993 pitch*height,
994 CONVERT_PALETTED,
995 This);
997 break;
999 default:
1000 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
1002 /* Give it a try */
1003 type = This->glDescription.glType;
1004 fmt = This->glDescription.glFormat;
1005 mem = This->resource.allocatedMemory;
1008 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1009 (This->lockedRect.bottom - This->lockedRect.top)-1,
1010 fmt, type,
1011 mem);
1012 checkGLcall("glDrawPixels");
1013 glPixelZoom(1.0,1.0);
1014 vcheckGLcall("glPixelZoom");
1016 glRasterPos3iv(&prev_rasterpos[0]);
1017 vcheckGLcall("glRasterPos3iv");
1019 /* Reset to previous pack row length */
1020 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1021 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1022 if(storechanged) {
1023 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
1024 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1027 if(mem != This->resource.allocatedMemory) HeapFree(GetProcessHeap(), 0, mem);
1028 return;
1031 static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
1032 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1033 float glTexCoord[4];
1035 glTexCoord[0] = 0.0; /* left */
1036 glTexCoord[1] = (float) This->currentDesc.Width / (float) This->pow2Width; /* right */
1037 glTexCoord[2] = 0.0; /* top */
1038 glTexCoord[3] = (float) This->currentDesc.Height / (float) This->pow2Height; /* bottom */
1040 IWineD3DSurface_PreLoad(iface);
1042 ENTER_GL();
1044 /* Disable some fancy graphics effects */
1045 glDisable(GL_LIGHTING);
1046 checkGLcall("glDisable GL_LIGHTING");
1047 glDisable(GL_DEPTH_TEST);
1048 checkGLcall("glDisable GL_DEPTH_TEST");
1049 glDisable(GL_FOG);
1050 checkGLcall("glDisable GL_FOG");
1051 glDisable(GL_CULL_FACE);
1052 checkGLcall("glDisable GL_CULL_FACE");
1053 glDisable(GL_BLEND);
1054 checkGLcall("glDisable GL_BLEND");
1055 glDisable(GL_STENCIL_TEST);
1056 checkGLcall("glDisable GL_STENCIL_TEST");
1058 glEnable(GL_TEXTURE_2D);
1059 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1060 checkGLcall("glEnable glBindTexture");
1062 /* No filtering for blts */
1063 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1064 checkGLcall("glTexParameteri");
1065 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1066 checkGLcall("glTexParameteri");
1068 /* Start drawing a quad */
1069 glBegin(GL_QUADS);
1071 glColor3d(1.0f, 1.0f, 1.0f);
1072 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1073 glVertex3f(0, 0, 0.0);
1075 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1076 glVertex3f(0, This->currentDesc.Height, 0.0);
1078 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1079 glVertex3d(This->currentDesc.Width, This->currentDesc.Height, 0.0);
1081 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1082 glVertex3f(This->currentDesc.Width, 0, 0.0);
1084 glEnd();
1085 checkGLcall("glEnd");
1087 /* Unbind the texture */
1088 glBindTexture(GL_TEXTURE_2D, 0);
1089 checkGLcall("glEnable glBindTexture");
1091 LEAVE_GL();
1094 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1095 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1096 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1097 const char *buffername = "";
1098 IWineD3DSwapChainImpl *swapchain = NULL;
1099 BOOL backbuf = FALSE;
1101 if (!(This->Flags & SFLAG_LOCKED)) {
1102 WARN("trying to Unlock an unlocked surf@%p\n", This);
1103 return WINED3DERR_INVALIDCALL;
1106 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
1107 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1109 if(swapchain) {
1110 int i;
1111 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
1112 if(iface == swapchain->backBuffer[i]) {
1113 backbuf = TRUE;
1114 break;
1119 if (backbuf) {
1120 buffername = "backBuffer";
1121 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
1122 buffername = "frontBuffer";
1123 } else if (iface == myDevice->depthStencilBuffer) {
1124 buffername = "depthStencilBuffer";
1125 } else if (iface == myDevice->renderTarget) {
1126 buffername = "renderTarget";
1130 if (swapchain != NULL) {
1131 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1134 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
1136 if (!(This->Flags & SFLAG_DIRTY)) {
1137 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1138 goto unlock_end;
1141 if (0 == This->resource.usage) { /* classic surface */
1143 * nothing to do
1144 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
1146 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
1148 /****************************
1149 * TODO: Render targets are 'special' and
1150 * ?some? locking needs to be passed onto the context manager
1151 * so that it becomes possible to use auxiliary buffers, pbuffers
1152 * render-to-texture, shared, cached contexts etc...
1153 * ****************************/
1154 IWineD3DSwapChainImpl *implSwapChain;
1155 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
1157 if (backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
1158 int tex;
1160 ENTER_GL();
1162 /* glDrawPixels transforms the raster position as though it was a vertex -
1163 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1164 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1165 d3ddevice_set_ortho(This->resource.wineD3DDevice);
1167 if (iface == implSwapChain->frontBuffer) {
1168 glDrawBuffer(GL_FRONT);
1169 checkGLcall("glDrawBuffer GL_FRONT");
1170 } else if (backbuf || iface == myDevice->renderTarget) {
1171 glDrawBuffer(GL_BACK);
1172 checkGLcall("glDrawBuffer GL_BACK");
1175 /* Disable higher textures before calling glDrawPixels */
1176 for(tex = 1; tex < GL_LIMITS(samplers); tex++) {
1177 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1178 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + tex));
1179 checkGLcall("glActiveTextureARB");
1181 glDisable(GL_TEXTURE_2D);
1182 checkGLcall("glDisable GL_TEXTURE_2D");
1183 glDisable(GL_TEXTURE_1D);
1184 checkGLcall("glDisable GL_TEXTURE_1D");
1186 /* Activate texture 0, but don't disable it necessarilly */
1187 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1188 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1189 checkGLcall("glActiveTextureARB");
1192 /* And back buffers are not blended. Disable the depth test,
1193 that helps performance */
1194 glDisable(GL_BLEND);
1195 glDisable(GL_DEPTH_TEST);
1196 glDisable(GL_FOG);
1198 switch(wined3d_settings.rendertargetlock_mode) {
1199 case RTL_AUTO:
1200 case RTL_READDRAW:
1201 case RTL_TEXDRAW:
1202 flush_to_framebuffer_drawpixels(This);
1203 break;
1205 case RTL_READTEX:
1206 case RTL_TEXTEX:
1207 flush_to_framebuffer_texture(iface);
1208 break;
1210 case RTL_DISABLE:
1212 static BOOL warned = FALSE;
1213 if(!warned) {
1214 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1215 warned = TRUE;
1218 break;
1221 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1222 glDrawBuffer(GL_BACK);
1223 vcheckGLcall("glDrawBuffer");
1225 if(myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_TRUE ||
1226 myDevice->stateBlock->renderState[D3DRS_ZENABLE] == D3DZB_USEW) glEnable(GL_DEPTH_TEST);
1227 if (myDevice->stateBlock->renderState[D3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1228 if (myDevice->stateBlock->renderState[D3DRS_FOGENABLE]) glEnable(GL_FOG);
1230 LEAVE_GL();
1232 /** restore clean dirty state */
1233 IWineD3DSurface_CleanDirtyRect(iface);
1235 } else {
1236 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1238 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1240 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1242 if (iface == myDevice->depthStencilBuffer) {
1243 FIXME("TODO stencil depth surface unlocking surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1244 } else {
1245 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1248 } else {
1249 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1252 unlock_end:
1253 This->Flags &= ~SFLAG_LOCKED;
1254 memset(&This->lockedRect, 0, sizeof(RECT));
1255 return WINED3D_OK;
1258 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1259 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1260 WINED3DLOCKED_RECT lock;
1261 UINT usage;
1262 BITMAPINFO* b_info;
1263 HDC ddc;
1264 DWORD *masks;
1265 HRESULT hr;
1266 RGBQUAD col[256];
1267 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1269 TRACE("(%p)->(%p)\n",This,pHDC);
1271 if(This->Flags & SFLAG_USERPTR) {
1272 ERR("Not supported on surfaces with an application-provided surfaces\n");
1273 return DDERR_NODC;
1276 /* Give more detailed info for ddraw */
1277 if (This->Flags & SFLAG_DCINUSE)
1278 return DDERR_DCALREADYCREATED;
1280 /* Can't GetDC if the surface is locked */
1281 if (This->Flags & SFLAG_LOCKED)
1282 return WINED3DERR_INVALIDCALL;
1284 memset(&lock, 0, sizeof(lock)); /* To be sure */
1286 /* Create a DIB section if there isn't a hdc yet */
1287 if(!This->hDC) {
1288 int extraline = 0;
1289 SYSTEM_INFO sysInfo;
1291 if(This->Flags & SFLAG_ACTIVELOCK) {
1292 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1295 switch (This->bytesPerPixel) {
1296 case 2:
1297 case 4:
1298 /* Allocate extra space to store the RGB bit masks. */
1299 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1300 break;
1302 case 3:
1303 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1304 break;
1306 default:
1307 /* Allocate extra space for a palette. */
1308 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1309 sizeof(BITMAPINFOHEADER)
1310 + sizeof(RGBQUAD)
1311 * (1 << (This->bytesPerPixel * 8)));
1312 break;
1315 if (!b_info)
1316 return E_OUTOFMEMORY;
1318 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1319 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1320 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1321 * add an extra line to the dib section
1323 GetSystemInfo(&sysInfo);
1324 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1325 extraline = 1;
1326 TRACE("Adding an extra line to the dib section\n");
1329 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1330 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1331 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1332 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1333 b_info->bmiHeader.biSizeImage = This->currentDesc.Width * This->currentDesc.Height * This->bytesPerPixel;
1334 /* Use the full pow2 image size(assigned below) because LockRect
1335 * will need it for a full glGetTexImage call
1337 } else {
1338 b_info->bmiHeader.biWidth = This->pow2Width;
1339 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1340 b_info->bmiHeader.biSizeImage = This->resource.size;
1342 b_info->bmiHeader.biPlanes = 1;
1343 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1345 b_info->bmiHeader.biXPelsPerMeter = 0;
1346 b_info->bmiHeader.biYPelsPerMeter = 0;
1347 b_info->bmiHeader.biClrUsed = 0;
1348 b_info->bmiHeader.biClrImportant = 0;
1350 /* Get the bit masks */
1351 masks = (DWORD *) &(b_info->bmiColors);
1352 switch (This->resource.format) {
1353 case WINED3DFMT_R8G8B8:
1354 usage = DIB_RGB_COLORS;
1355 b_info->bmiHeader.biCompression = BI_RGB;
1356 break;
1358 case WINED3DFMT_X1R5G5B5:
1359 case WINED3DFMT_A1R5G5B5:
1360 case WINED3DFMT_A4R4G4B4:
1361 case WINED3DFMT_X4R4G4B4:
1362 case WINED3DFMT_R3G3B2:
1363 case WINED3DFMT_A8R3G3B2:
1364 case WINED3DFMT_A2B10G10R10:
1365 case WINED3DFMT_A8B8G8R8:
1366 case WINED3DFMT_X8B8G8R8:
1367 case WINED3DFMT_A2R10G10B10:
1368 case WINED3DFMT_R5G6B5:
1369 case WINED3DFMT_A16B16G16R16:
1370 usage = 0;
1371 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1372 masks[0] = formatEntry->redMask;
1373 masks[1] = formatEntry->greenMask;
1374 masks[2] = formatEntry->blueMask;
1375 break;
1377 default:
1378 /* Don't know palette */
1379 b_info->bmiHeader.biCompression = BI_RGB;
1380 usage = 0;
1381 break;
1384 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1385 if (ddc == 0) {
1386 HeapFree(GetProcessHeap(), 0, b_info);
1387 return HRESULT_FROM_WIN32(GetLastError());
1390 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);
1391 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1392 DeleteDC(ddc);
1394 if (!This->dib.DIBsection) {
1395 ERR("CreateDIBSection failed!\n");
1396 HeapFree(GetProcessHeap(), 0, b_info);
1397 return HRESULT_FROM_WIN32(GetLastError());
1400 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1402 /* copy the existing surface to the dib section */
1403 if(This->resource.allocatedMemory) {
1404 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1405 /* We won't need that any more */
1406 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1407 } else {
1408 /* This is to make LockRect read the gl Texture although memory is allocated */
1409 This->Flags |= SFLAG_GLDIRTY;
1412 HeapFree(GetProcessHeap(), 0, b_info);
1414 /* Use the dib section from now on */
1415 This->resource.allocatedMemory = This->dib.bitmap_data;
1417 /* Now allocate a HDC */
1418 This->hDC = CreateCompatibleDC(0);
1419 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1420 TRACE("using wined3d palette %p\n", This->palette);
1421 SelectPalette(This->hDC,
1422 This->palette ? This->palette->hpal : 0,
1423 FALSE);
1425 This->Flags |= SFLAG_DIBSECTION;
1428 /* Lock the surface */
1429 hr = IWineD3DSurface_LockRect(iface,
1430 &lock,
1431 NULL,
1433 if(FAILED(hr)) {
1434 ERR("IWineD3DSurface_LockRect failed with hr = %08lx\n", hr);
1435 /* keep the dib section */
1436 return hr;
1439 if(This->resource.format == WINED3DFMT_P8 ||
1440 This->resource.format == WINED3DFMT_A8P8) {
1441 unsigned int n;
1442 if(This->palette) {
1443 PALETTEENTRY ent[256];
1445 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1446 for (n=0; n<256; n++) {
1447 col[n].rgbRed = ent[n].peRed;
1448 col[n].rgbGreen = ent[n].peGreen;
1449 col[n].rgbBlue = ent[n].peBlue;
1450 col[n].rgbReserved = 0;
1452 } else {
1453 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1455 for (n=0; n<256; n++) {
1456 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1457 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1458 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1459 col[n].rgbReserved = 0;
1463 SetDIBColorTable(This->hDC, 0, 256, col);
1466 *pHDC = This->hDC;
1467 TRACE("returning %p\n",*pHDC);
1468 This->Flags |= SFLAG_DCINUSE;
1470 return WINED3D_OK;
1473 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1474 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1476 TRACE("(%p)->(%p)\n",This,hDC);
1478 if (!(This->Flags & SFLAG_DCINUSE))
1479 return D3DERR_INVALIDCALL;
1481 /* we locked first, so unlock now */
1482 IWineD3DSurface_UnlockRect(iface);
1484 This->Flags &= ~SFLAG_DCINUSE;
1486 return WINED3D_OK;
1489 /* ******************************************************
1490 IWineD3DSurface Internal (No mapping to directx api) parts follow
1491 ****************************************************** */
1493 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1494 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1495 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1497 /* Default values: From the surface */
1498 *format = formatEntry->glFormat;
1499 *internal = formatEntry->glInternal;
1500 *type = formatEntry->glType;
1501 *convert = NO_CONVERSION;
1502 *target_bpp = This->bytesPerPixel;
1504 /* Ok, now look if we have to do any conversion */
1505 switch(This->resource.format) {
1506 case WINED3DFMT_P8:
1507 /* ****************
1508 Paletted Texture
1509 **************** */
1510 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1511 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1513 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1514 *format = GL_RGBA;
1515 *internal = GL_RGBA;
1516 *type = GL_UNSIGNED_BYTE;
1517 *target_bpp = 4;
1518 if(colorkey_active) {
1519 *convert = CONVERT_PALETTED_CK;
1520 } else {
1521 *convert = CONVERT_PALETTED;
1525 break;
1527 case WINED3DFMT_R3G3B2:
1528 /* **********************
1529 GL_UNSIGNED_BYTE_3_3_2
1530 ********************** */
1531 if (colorkey_active) {
1532 /* This texture format will never be used.. So do not care about color keying
1533 up until the point in time it will be needed :-) */
1534 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1536 break;
1538 case WINED3DFMT_R5G6B5:
1539 if (colorkey_active) {
1540 *convert = CONVERT_CK_565;
1541 *format = GL_RGBA;
1542 *internal = GL_RGBA;
1543 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1545 break;
1547 case WINED3DFMT_R8G8B8:
1548 if (colorkey_active) {
1549 *convert = CONVERT_CK_RGB24;
1550 *format = GL_RGBA;
1551 *internal = GL_RGBA;
1552 *type = GL_UNSIGNED_INT_8_8_8_8;
1553 *target_bpp = 4;
1555 break;
1557 case WINED3DFMT_X8R8G8B8:
1558 if (colorkey_active) {
1559 *convert = CONVERT_RGB32_888;
1560 *format = GL_RGBA;
1561 *internal = GL_RGBA;
1562 *type = GL_UNSIGNED_INT_8_8_8_8;
1564 break;
1565 #if 0
1566 /* Not sure if we should do color keying on Alpha-Enabled surfaces */
1567 case WINED3DFMT_A4R4G4B4:
1568 if (colorkey_active)
1570 *convert = CONVERT_CK_4444_ARGB;
1571 *format = GL_RGBA;
1572 *internal = GL_RGBA;
1573 *type = GL_UNSIGNED_SHORT_4_4_4_4;
1575 break;
1577 case WINED3DFMT_A1R5G5B5:
1578 if (colorkey_active)
1580 *convert = CONVERT_CK_1555;
1583 case WINED3DFMT_A8R8G8B8:
1584 if (colorkey_active)
1586 *convert = CONVERT_CK_8888_ARGB;
1587 *format = GL_RGBA;
1588 *internal = GL_RGBA;
1589 *type = GL_UNSIGNED_INT_8_8_8_8;
1591 break;
1592 #endif
1593 default:
1594 break;
1597 return WINED3D_OK;
1600 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, unsigned long len, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1601 TRACE("(%p)->(%p),(%ld,%d,%p)\n", src, dst, len, convert, surf);
1603 switch (convert) {
1604 case NO_CONVERSION:
1606 memcpy(dst, src, len * surf->bytesPerPixel);
1607 break;
1609 case CONVERT_PALETTED:
1610 case CONVERT_PALETTED_CK:
1612 IWineD3DPaletteImpl* pal = surf->palette;
1613 BYTE table[256][4];
1614 unsigned int i;
1615 unsigned int x;
1617 if( pal == NULL) {
1618 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1621 if (pal == NULL) {
1622 /* Still no palette? Use the device's palette */
1623 /* Get the surface's palette */
1624 for (i = 0; i < 256; i++) {
1625 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1627 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1628 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1629 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1630 if ((convert == CONVERT_PALETTED_CK) &&
1631 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1632 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1633 /* We should maybe here put a more 'neutral' color than the standard bright purple
1634 one often used by application to prevent the nice purple borders when bi-linear
1635 filtering is on */
1636 table[i][3] = 0x00;
1637 } else {
1638 table[i][3] = 0xFF;
1641 } else {
1642 TRACE("Using surface palette %p\n", pal);
1643 /* Get the surface's palette */
1644 for (i = 0; i < 256; i++) {
1645 table[i][0] = pal->palents[i].peRed;
1646 table[i][1] = pal->palents[i].peGreen;
1647 table[i][2] = pal->palents[i].peBlue;
1648 if ((convert == CONVERT_PALETTED_CK) &&
1649 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1650 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1651 /* We should maybe here put a more 'neutral' color than the standard bright purple
1652 one often used by application to prevent the nice purple borders when bi-linear
1653 filtering is on */
1654 table[i][3] = 0x00;
1655 } else {
1656 table[i][3] = 0xFF;
1661 for (x = 0; x < len; x++) {
1662 BYTE color = *src++;
1663 *dst++ = table[color][0];
1664 *dst++ = table[color][1];
1665 *dst++ = table[color][2];
1666 *dst++ = table[color][3];
1669 break;
1671 case CONVERT_CK_565:
1673 /* Converting the 565 format in 5551 packed to emulate color-keying.
1675 Note : in all these conversion, it would be best to average the averaging
1676 pixels to get the color of the pixel that will be color-keyed to
1677 prevent 'color bleeding'. This will be done later on if ever it is
1678 too visible.
1680 Note2: when using color-keying + alpha, are the alpha bits part of the
1681 color-space or not ?
1683 unsigned int x;
1684 WORD *Source = (WORD *) src;
1685 WORD *Dest = (WORD *) dst;
1687 TRACE("Color keyed 565\n");
1689 for (x = 0; x < len; x++ ) {
1690 WORD color = *Source++;
1691 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1692 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1693 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1694 *Dest |= 0x0001;
1696 Dest++;
1699 break;
1701 case CONVERT_CK_1555:
1703 unsigned int x;
1704 WORD *Source = (WORD *) src;
1705 WORD *Dest = (WORD *) dst;
1707 for (x = 0; x < len * sizeof(WORD); x+=sizeof(WORD)) {
1708 WORD color = *Source++;
1709 *Dest = (color & 0x7FFF);
1710 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1711 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1712 *Dest |= (color & 0x8000);
1713 Dest++;
1716 break;
1718 case CONVERT_CK_4444_ARGB:
1720 /* Move the four Alpha bits... */
1721 unsigned int x;
1722 WORD *Source = (WORD *) src;
1723 WORD *Dest = (WORD *) dst;
1725 for (x = 0; x < len; x++) {
1726 WORD color = *Source++;
1727 *dst = (color & 0x0FFF) << 4;
1728 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1729 (color > surf->SrcBltCKey.dwColorSpaceHighValue))
1730 *Dest |= (color & 0xF000) >> 12;
1731 Dest++;
1733 } break;
1735 default:
1736 ERR("Unsupported conversation type %d\n", convert);
1739 return WINED3D_OK;
1742 /* This function is used in case of 8bit paletted textures to upload the palette.
1743 For now it only supports GL_EXT_paletted_texture extension but support for other
1744 extensions like ARB_fragment_program and ATI_fragment_shaders will be added aswell.
1746 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1747 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1748 IWineD3DPaletteImpl* pal = This->palette;
1749 BYTE table[256][4];
1750 int i;
1752 if (pal == NULL) {
1753 /* Still no palette? Use the device's palette */
1754 /* Get the surface's palette */
1755 for (i = 0; i < 256; i++) {
1756 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1758 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1759 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1760 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1761 if ((convert == CONVERT_PALETTED_CK) &&
1762 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1763 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1764 /* We should maybe here put a more 'neutral' color than the standard bright purple
1765 one often used by application to prevent the nice purple borders when bi-linear
1766 filtering is on */
1767 table[i][3] = 0x00;
1768 } else {
1769 table[i][3] = 0xFF;
1772 } else {
1773 TRACE("Using surface palette %p\n", pal);
1774 /* Get the surface's palette */
1775 for (i = 0; i < 256; i++) {
1776 table[i][0] = pal->palents[i].peRed;
1777 table[i][1] = pal->palents[i].peGreen;
1778 table[i][2] = pal->palents[i].peBlue;
1779 if ((convert == CONVERT_PALETTED_CK) &&
1780 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1781 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1782 /* We should maybe here put a more 'neutral' color than the standard bright purple
1783 one often used by application to prevent the nice purple borders when bi-linear
1784 filtering is on */
1785 table[i][3] = 0x00;
1786 } else {
1787 table[i][3] = 0xFF;
1791 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1794 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1795 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1796 GLenum format, internal, type;
1797 CONVERT_TYPES convert;
1798 int bpp;
1799 int pitch;
1800 BYTE *mem;
1802 if (This->Flags & SFLAG_INTEXTURE) {
1803 TRACE("Surface already in texture\n");
1804 return WINED3D_OK;
1806 if (This->Flags & SFLAG_DIRTY) {
1807 TRACE("Reloading because surface is dirty\n");
1808 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1809 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1810 /* Reload: vice versa OR */
1811 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1812 /* Also reload: Color key is active AND the color key has changed */
1813 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1814 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1815 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1816 TRACE("Reloading because of color keying\n");
1817 } else {
1818 TRACE("surface isn't dirty\n");
1819 return WINED3D_OK;
1822 This->Flags &= ~SFLAG_DIRTY;
1824 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1825 * These resources are not bound by device size or format restrictions. Because of this,
1826 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1827 * However, these resources can always be created, locked, and copied.
1829 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1831 FIXME("(%p) Operation not supported for scratch textures\n",This);
1832 return WINED3DERR_INVALIDCALL;
1835 if (This->Flags & SFLAG_INPBUFFER) {
1836 if (This->glDescription.level != 0)
1837 FIXME("Surface in texture is only supported for level 0\n");
1838 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1839 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1840 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1841 This->resource.format == WINED3DFMT_DXT5)
1842 FIXME("Format %d not supported\n", This->resource.format);
1843 else {
1844 GLint prevRead;
1846 ENTER_GL();
1848 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1849 vcheckGLcall("glGetIntegerv");
1850 glReadBuffer(GL_BACK);
1851 vcheckGLcall("glReadBuffer");
1853 glCopyTexImage2D(This->glDescription.target,
1854 This->glDescription.level,
1855 This->glDescription.glFormatInternal,
1858 This->currentDesc.Width,
1859 This->currentDesc.Height,
1862 checkGLcall("glCopyTexImage2D");
1863 glReadBuffer(prevRead);
1864 vcheckGLcall("glReadBuffer");
1866 LEAVE_GL();
1868 TRACE("Updating target %d\n", This->glDescription.target);
1869 This->Flags |= SFLAG_INTEXTURE;
1871 return WINED3D_OK;
1874 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1875 This->Flags |= SFLAG_GLCKEY;
1876 This->glCKey = This->SrcBltCKey;
1878 else This->Flags &= ~SFLAG_GLCKEY;
1880 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1882 /* The pitch is in 'length' not in bytes */
1883 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1884 pitch = This->currentDesc.Width;
1885 else
1886 pitch = This->pow2Width;
1888 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1889 int height = This->glRect.bottom - This->glRect.top;
1891 mem = HeapAlloc(GetProcessHeap(), 0, pitch * height * bpp);
1892 if(!mem) {
1893 ERR("Out of memory %d, %d!\n", pitch, height);
1894 return WINED3DERR_OUTOFVIDEOMEMORY;
1896 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch * height, convert, This);
1898 This->Flags |= SFLAG_CONVERTED;
1899 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1900 d3dfmt_p8_upload_palette(iface, convert);
1901 This->Flags &= ~SFLAG_CONVERTED;
1902 mem = This->resource.allocatedMemory;
1903 } else {
1904 This->Flags &= ~SFLAG_CONVERTED;
1905 mem = This->resource.allocatedMemory;
1908 /* Make sure the correct pitch is used */
1909 glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch);
1911 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1912 TRACE("non power of two support\n");
1913 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1914 if (mem) {
1915 surface_upload_data(This, This->pow2Width, This->pow2Height, format, type, mem);
1917 } else {
1918 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1919 if (mem) {
1920 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1924 /* Restore the default pitch */
1925 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1927 if (mem != This->resource.allocatedMemory)
1928 HeapFree(GetProcessHeap(), 0, mem);
1930 #if 0
1932 static unsigned int gen = 0;
1933 char buffer[4096];
1934 ++gen;
1935 if ((gen % 10) == 0) {
1936 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1937 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1940 * debugging crash code
1941 if (gen == 250) {
1942 void** test = NULL;
1943 *test = 0;
1947 #endif
1949 if (!(This->Flags & SFLAG_DONOTFREE)) {
1950 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1951 This->resource.allocatedMemory = NULL;
1954 return WINED3D_OK;
1957 #include <errno.h>
1958 #include <stdio.h>
1959 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1960 FILE* f = NULL;
1961 UINT i, y;
1962 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1963 char *allocatedMemory;
1964 char *textureRow;
1965 IWineD3DSwapChain *swapChain = NULL;
1966 int width, height;
1967 GLuint tmpTexture = 0;
1968 DWORD color;
1969 /*FIXME:
1970 Textures my not be stored in ->allocatedgMemory and a GlTexture
1971 so we should lock the surface before saving a snapshot, or at least check that
1973 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1974 by calling GetTexImage and in compressed form by calling
1975 GetCompressedTexImageARB. Queried compressed images can be saved and
1976 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1977 texture images do not need to be processed by the GL and should
1978 significantly improve texture loading performance relative to uncompressed
1979 images. */
1981 /* Setup the width and height to be the internal texture width and height. */
1982 width = This->pow2Width;
1983 height = This->pow2Height;
1984 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1985 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1987 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1988 /* 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 */
1989 GLint prevRead;
1990 ENTER_GL();
1991 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1992 glEnable(GL_TEXTURE_2D);
1994 glGenTextures(1, &tmpTexture);
1995 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1997 glTexImage2D(GL_TEXTURE_2D,
1999 GL_RGBA,
2000 width,
2001 height,
2002 0/*border*/,
2003 GL_RGBA,
2004 GL_UNSIGNED_INT_8_8_8_8_REV,
2005 NULL);
2007 glGetIntegerv(GL_READ_BUFFER, &prevRead);
2008 vcheckGLcall("glGetIntegerv");
2009 glReadBuffer(GL_BACK);
2010 vcheckGLcall("glReadBuffer");
2011 glCopyTexImage2D(GL_TEXTURE_2D,
2013 GL_RGBA,
2016 width,
2017 height,
2020 checkGLcall("glCopyTexImage2D");
2021 glReadBuffer(prevRead);
2022 LEAVE_GL();
2024 } else { /* bind the real texture */
2025 IWineD3DSurface_PreLoad(iface);
2027 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
2028 ENTER_GL();
2029 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
2030 glGetTexImage(GL_TEXTURE_2D,
2031 This->glDescription.level,
2032 GL_RGBA,
2033 GL_UNSIGNED_INT_8_8_8_8_REV,
2034 allocatedMemory);
2035 checkGLcall("glTexImage2D");
2036 if (tmpTexture) {
2037 glBindTexture(GL_TEXTURE_2D, 0);
2038 glDeleteTextures(1, &tmpTexture);
2040 LEAVE_GL();
2042 f = fopen(filename, "w+");
2043 if (NULL == f) {
2044 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2045 return WINED3DERR_INVALIDCALL;
2047 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
2048 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2049 /* TGA header */
2050 fputc(0,f);
2051 fputc(0,f);
2052 fputc(2,f);
2053 fputc(0,f);
2054 fputc(0,f);
2055 fputc(0,f);
2056 fputc(0,f);
2057 fputc(0,f);
2058 fputc(0,f);
2059 fputc(0,f);
2060 fputc(0,f);
2061 fputc(0,f);
2062 /* short width*/
2063 fwrite(&width,2,1,f);
2064 /* short height */
2065 fwrite(&height,2,1,f);
2066 /* format rgba */
2067 fputc(0x20,f);
2068 fputc(0x28,f);
2069 /* raw data */
2070 /* 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*/
2071 if(swapChain)
2072 textureRow = allocatedMemory + (width * (height - 1) *4);
2073 else
2074 textureRow = allocatedMemory;
2075 for (y = 0 ; y < height; y++) {
2076 for (i = 0; i < width; i++) {
2077 color = *((DWORD*)textureRow);
2078 fputc((color >> 16) & 0xFF, f); /* B */
2079 fputc((color >> 8) & 0xFF, f); /* G */
2080 fputc((color >> 0) & 0xFF, f); /* R */
2081 fputc((color >> 24) & 0xFF, f); /* A */
2082 textureRow += 4;
2084 /* take two rows of the pointer to the texture memory */
2085 if(swapChain)
2086 (textureRow-= width << 3);
2089 TRACE("Closing file\n");
2090 fclose(f);
2092 if(swapChain) {
2093 IWineD3DSwapChain_Release(swapChain);
2095 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2096 return WINED3D_OK;
2099 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2100 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2101 This->Flags &= ~SFLAG_DIRTY;
2102 This->dirtyRect.left = This->currentDesc.Width;
2103 This->dirtyRect.top = This->currentDesc.Height;
2104 This->dirtyRect.right = 0;
2105 This->dirtyRect.bottom = 0;
2106 TRACE("(%p) : Dirty?%d, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2107 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2108 return WINED3D_OK;
2112 * Slightly inefficient way to handle multiple dirty rects but it works :)
2114 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2115 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2116 IWineD3DBaseTexture *baseTexture = NULL;
2117 This->Flags |= SFLAG_DIRTY;
2118 if (NULL != pDirtyRect) {
2119 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2120 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2121 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2122 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2123 } else {
2124 This->dirtyRect.left = 0;
2125 This->dirtyRect.top = 0;
2126 This->dirtyRect.right = This->currentDesc.Width;
2127 This->dirtyRect.bottom = This->currentDesc.Height;
2129 TRACE("(%p) : Dirty?%ld, Rect:(%ld,%ld,%ld,%ld)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2130 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2131 /* if the container is a basetexture then mark it dirty. */
2132 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2133 TRACE("Passing to conatiner\n");
2134 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2135 IWineD3DBaseTexture_Release(baseTexture);
2137 return WINED3D_OK;
2140 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2141 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2143 TRACE("This %p, container %p\n", This, container);
2145 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2147 TRACE("Setting container to %p from %p\n", container, This->container);
2148 This->container = container;
2150 return WINED3D_OK;
2153 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2154 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2155 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2157 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2158 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2159 return WINED3DERR_INVALIDCALL;
2162 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2163 if (format == WINED3DFMT_UNKNOWN) {
2164 This->resource.size = 0;
2165 } else if (format == WINED3DFMT_DXT1) {
2166 /* DXT1 is half byte per pixel */
2167 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2169 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2170 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2171 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2172 } else {
2173 This->resource.size = (This->pow2Width * formatEntry->bpp) * This->pow2Height;
2177 /* Setup some glformat defaults */
2178 This->glDescription.glFormat = formatEntry->glFormat;
2179 This->glDescription.glFormatInternal = formatEntry->glInternal;
2180 This->glDescription.glType = formatEntry->glType;
2182 if (format != WINED3DFMT_UNKNOWN) {
2183 This->bytesPerPixel = formatEntry->bpp;
2184 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2185 } else {
2186 This->bytesPerPixel = 0;
2187 This->pow2Size = 0;
2190 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2192 This->resource.format = format;
2194 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);
2196 return WINED3D_OK;
2199 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2200 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2202 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2203 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2204 ERR("Not supported on render targets\n");
2205 return WINED3DERR_INVALIDCALL;
2208 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2209 WARN("Surface is locked or the HDC is in use\n");
2210 return WINED3DERR_INVALIDCALL;
2213 if(Mem && Mem != This->resource.allocatedMemory) {
2215 /* Do I have to copy the old surface content? */
2216 if(This->Flags & SFLAG_DIBSECTION) {
2217 /* Release the DC. No need to hold the critical section for the update
2218 * Thread because this thread runs only on front buffers, but this method
2219 * fails for render targets in the check above.
2221 SelectObject(This->hDC, This->dib.holdbitmap);
2222 DeleteDC(This->hDC);
2223 /* Release the DIB section */
2224 DeleteObject(This->dib.DIBsection);
2225 This->dib.bitmap_data = NULL;
2226 This->resource.allocatedMemory = NULL;
2227 This->hDC = NULL;
2228 This->Flags &= ~SFLAG_DIBSECTION;
2229 } else if(!(This->Flags & SFLAG_USERPTR)) {
2230 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2232 This->resource.allocatedMemory = Mem;
2233 This->Flags |= SFLAG_USERPTR;
2234 } else if(This->Flags & SFLAG_USERPTR) {
2235 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2236 This->resource.allocatedMemory = NULL;
2237 This->Flags &= ~SFLAG_USERPTR;
2239 return WINED3D_OK;
2242 /* TODO: replace this function with context management routines */
2243 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2244 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2246 if(inPBuffer) {
2247 This->Flags |= SFLAG_INPBUFFER;
2248 } else {
2249 This->Flags &= ~SFLAG_INPBUFFER;
2252 if(inTexture) {
2253 This->Flags |= SFLAG_INTEXTURE;
2254 } else {
2255 This->Flags &= ~SFLAG_INTEXTURE;
2258 return WINED3D_OK;
2261 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2262 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2263 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2264 TRACE("(%p)->(%p,%lx)\n", This, override, Flags);
2266 /* Flipping is only supported on RenderTargets */
2267 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2269 if(override) {
2270 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2271 * FIXME("(%p) Target override is not supported by now\n", This);
2272 * Additionally, it isn't really possible to support triple-buffering
2273 * properly on opengl at all
2277 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2278 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2281 /* Not called from the VTable */
2282 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2283 D3DRECT rect;
2284 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2285 IWineD3DSwapChainImpl *swapchain = NULL;
2286 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2287 BOOL SrcOK = TRUE;
2289 TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2291 /* Get the swapchain. One of the surfaces has to be a primary surface */
2292 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2293 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2294 else if(Src) {
2295 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2296 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2297 else return WINED3DERR_INVALIDCALL;
2298 } else {
2299 swapchain = NULL;
2302 if (DestRect) {
2303 rect.x1 = DestRect->left;
2304 rect.y1 = DestRect->top;
2305 rect.x2 = DestRect->right;
2306 rect.y2 = DestRect->bottom;
2307 } else {
2308 rect.x1 = 0;
2309 rect.y1 = 0;
2310 rect.x2 = This->currentDesc.Width;
2311 rect.y2 = This->currentDesc.Height;
2314 /* Half-life does a Blt from the back buffer to the front buffer,
2315 * Full surface size, no flags... Use present instead
2317 if(Src)
2319 /* First, check if we can do a Flip */
2321 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2322 if( SrcRect ) {
2323 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2324 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2325 SrcOK = TRUE;
2327 } else {
2328 SrcOK = TRUE;
2331 /* Check the Destination rect and the surface sizes */
2332 if(SrcOK &&
2333 (rect.x1 == 0) && (rect.y1 == 0) &&
2334 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2335 (This->currentDesc.Width == Src->currentDesc.Width) &&
2336 (This->currentDesc.Height == Src->currentDesc.Height)) {
2337 /* These flags are unimportant for the flag check, remove them */
2339 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2340 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2342 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2344 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2345 * take very long, while a flip is fast.
2346 * This applies to Half-Life, which does such Blts every time it finished
2347 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2348 * menu. This is also used by all apps when they do windowed rendering
2350 * The problem is that flipping is not really the same as copying. After a
2351 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2352 * untouched. Therefore it's necessary to override the swap effect
2353 * and to set it back after the flip.
2356 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2358 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2359 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2360 NULL, NULL, 0, NULL);
2362 swapchain->presentParms.SwapEffect = orig_swap;
2364 return WINED3D_OK;
2369 /* Blt from texture to rendertarget? */
2370 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2371 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2373 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2374 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2375 float glTexCoord[4];
2376 DWORD oldCKey;
2377 DDCOLORKEY oldBltCKey = {0,0};
2378 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2379 GLint alphafunc;
2380 GLclampf alpharef;
2381 GLint oldStencil;
2382 RECT SourceRectangle;
2383 GLint oldDraw;
2385 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2387 if(SrcRect) {
2388 SourceRectangle.left = SrcRect->left;
2389 SourceRectangle.right = SrcRect->right;
2390 SourceRectangle.top = SrcRect->top;
2391 SourceRectangle.bottom = SrcRect->bottom;
2392 } else {
2393 SourceRectangle.left = 0;
2394 SourceRectangle.right = Src->currentDesc.Width;
2395 SourceRectangle.top = 0;
2396 SourceRectangle.bottom = Src->currentDesc.Height;
2399 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2400 /* Fall back to software */
2401 WARN("(%p) Source texture area (%ld,%ld)-(%ld,%ld) is too big\n", Src,
2402 SourceRectangle.left, SourceRectangle.top,
2403 SourceRectangle.right, SourceRectangle.bottom);
2404 return WINED3DERR_INVALIDCALL;
2407 /* Color keying: Check if we have to do a color keyed blt,
2408 * and if not check if a color key is activated.
2410 oldCKey = Src->CKeyFlags;
2411 if(!(Flags & DDBLT_KEYSRC) &&
2412 Src->CKeyFlags & DDSD_CKSRCBLT) {
2413 /* Ok, the surface has a color key, but we shall not use it -
2414 * Deactivate it for now, LoadTexture will catch this
2416 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2419 /* Color keying */
2420 if(Flags & DDBLT_KEYDEST) {
2421 oldBltCKey = This->SrcBltCKey;
2422 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2423 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2425 This->SrcBltCKey = This->DestBltCKey;
2426 } else if (Flags & DDBLT_KEYSRC)
2427 oldBltCKey = This->SrcBltCKey;
2429 /* Now load the surface */
2430 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2432 ENTER_GL();
2434 /* Save all the old stuff until we have a proper opengl state manager */
2435 oldLight = glIsEnabled(GL_LIGHTING);
2436 oldFog = glIsEnabled(GL_FOG);
2437 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2438 oldBlend = glIsEnabled(GL_BLEND);
2439 oldCull = glIsEnabled(GL_CULL_FACE);
2440 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2441 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2443 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2444 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2445 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2446 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2448 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2449 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2450 TRACE("Drawing to front buffer\n");
2451 glDrawBuffer(GL_FRONT);
2452 checkGLcall("glDrawBuffer GL_FRONT");
2455 /* Unbind the old texture */
2456 glBindTexture(GL_TEXTURE_2D, 0);
2458 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2459 /* We use texture unit 0 for blts */
2460 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2461 checkGLcall("glActiveTextureARB");
2462 } else {
2463 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2466 /* Disable some fancy graphics effects */
2467 glDisable(GL_LIGHTING);
2468 checkGLcall("glDisable GL_LIGHTING");
2469 glDisable(GL_DEPTH_TEST);
2470 checkGLcall("glDisable GL_DEPTH_TEST");
2471 glDisable(GL_FOG);
2472 checkGLcall("glDisable GL_FOG");
2473 glDisable(GL_BLEND);
2474 checkGLcall("glDisable GL_BLEND");
2475 glDisable(GL_CULL_FACE);
2476 checkGLcall("glDisable GL_CULL_FACE");
2477 glDisable(GL_STENCIL_TEST);
2478 checkGLcall("glDisable GL_STENCIL_TEST");
2480 /* Ok, we need 2d textures, but not 1D or 3D */
2481 glDisable(GL_TEXTURE_1D);
2482 checkGLcall("glDisable GL_TEXTURE_1D");
2483 glEnable(GL_TEXTURE_2D);
2484 checkGLcall("glEnable GL_TEXTURE_2D");
2485 glDisable(GL_TEXTURE_3D);
2486 checkGLcall("glDisable GL_TEXTURE_3D");
2488 /* Bind the texture */
2489 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2490 checkGLcall("glBindTexture");
2492 glEnable(GL_SCISSOR_TEST);
2494 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2496 /* No filtering for blts */
2497 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2498 GL_NEAREST);
2499 checkGLcall("glTexParameteri");
2500 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2501 GL_NEAREST);
2502 checkGLcall("glTexParameteri");
2503 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2504 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2505 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2506 checkGLcall("glTexEnvi");
2508 /* This is for color keying */
2509 if(Flags & DDBLT_KEYSRC) {
2510 glEnable(GL_ALPHA_TEST);
2511 checkGLcall("glEnable GL_ALPHA_TEST");
2512 glAlphaFunc(GL_NOTEQUAL, 0.0);
2513 checkGLcall("glAlphaFunc\n");
2514 } else {
2515 glDisable(GL_ALPHA_TEST);
2516 checkGLcall("glDisable GL_ALPHA_TEST");
2519 /* Draw a textured quad
2521 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2523 glBegin(GL_QUADS);
2525 glColor3d(1.0f, 1.0f, 1.0f);
2526 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2527 glVertex3f(rect.x1,
2528 rect.y1,
2529 0.0);
2531 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2532 glVertex3f(rect.x1, rect.y2, 0.0);
2534 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2535 glVertex3f(rect.x2,
2536 rect.y2,
2537 0.0);
2539 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2540 glVertex3f(rect.x2,
2541 rect.y1,
2542 0.0);
2543 glEnd();
2544 checkGLcall("glEnd");
2546 /* Unbind the texture */
2547 glBindTexture(GL_TEXTURE_2D, 0);
2548 checkGLcall("glEnable glBindTexture");
2550 /* Restore the old settings */
2551 if(oldLight) {
2552 glEnable(GL_LIGHTING);
2553 checkGLcall("glEnable GL_LIGHTING");
2555 if(oldFog) {
2556 glEnable(GL_FOG);
2557 checkGLcall("glEnable GL_FOG");
2559 if(oldDepth) {
2560 glEnable(GL_DEPTH_TEST);
2561 checkGLcall("glEnable GL_DEPTH_TEST");
2563 if(oldBlend) {
2564 glEnable(GL_BLEND);
2565 checkGLcall("glEnable GL_BLEND");
2567 if(oldCull) {
2568 glEnable(GL_CULL_FACE);
2569 checkGLcall("glEnable GL_CULL_FACE");
2571 if(oldStencil) {
2572 glEnable(GL_STENCIL_TEST);
2573 checkGLcall("glEnable GL_STENCIL_TEST");
2575 if(!oldAlpha) {
2576 glDisable(GL_ALPHA_TEST);
2577 checkGLcall("glDisable GL_ALPHA_TEST");
2578 } else {
2579 glEnable(GL_ALPHA_TEST);
2580 checkGLcall("glEnable GL_ALPHA_TEST");
2583 glAlphaFunc(alphafunc, alpharef);
2584 checkGLcall("glAlphaFunc\n");
2586 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2587 glDrawBuffer(oldDraw);
2590 /* Restore the color key flags */
2591 if(oldCKey != Src->CKeyFlags) {
2592 Src->CKeyFlags = oldCKey;
2595 /* Restore the old color key */
2596 if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
2597 This->SrcBltCKey = oldBltCKey;
2599 LEAVE_GL();
2601 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2602 This->Flags |= SFLAG_GLDIRTY;
2604 return WINED3D_OK;
2608 /* Blt from rendertarget to texture? */
2609 if( (SrcSurface == swapchain->frontBuffer) ||
2610 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2611 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2612 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2613 UINT row;
2614 D3DRECT srect;
2615 float xrel, yrel;
2617 TRACE("Blt from rendertarget to texture\n");
2619 /* Call preload for the surface to make sure it isn't dirty */
2620 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2622 if(SrcRect) {
2623 srect.x1 = SrcRect->left;
2624 srect.y1 = SrcRect->top;
2625 srect.x2 = SrcRect->right;
2626 srect.y2 = SrcRect->bottom;
2627 } else {
2628 srect.x1 = 0;
2629 srect.y1 = 0;
2630 srect.x2 = Src->currentDesc.Width;
2631 srect.y2 = Src->currentDesc.Height;
2634 ENTER_GL();
2636 /* Bind the target texture */
2637 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2638 checkGLcall("glBindTexture");
2639 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2640 glReadBuffer(GL_BACK);
2641 } else {
2642 glReadBuffer(GL_FRONT);
2644 checkGLcall("glReadBuffer");
2646 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2647 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2649 /* I have to process this row by row to swap the image,
2650 * otherwise it would be upside down, so streching in y direction
2651 * doesn't cost extra time
2653 * However, streching in x direction can be avoided if not necessary
2655 for(row = rect.y1; row < rect.y2; row++) {
2656 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2657 /* Well, that stuff works, but it's very slow.
2658 * find a better way instead
2660 UINT col;
2661 for(col = rect.x1; col < rect.x2; col++) {
2662 glCopyTexSubImage2D(GL_TEXTURE_2D,
2663 0, /* level */
2664 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2665 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2666 1, 1);
2668 } else {
2669 glCopyTexSubImage2D(GL_TEXTURE_2D,
2670 0, /* level */
2671 rect.x1, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2672 srect.x1, Src->currentDesc.Height - srect.y2 + row * yrel,
2673 rect.x2, 1);
2677 vcheckGLcall("glCopyTexSubImage2D");
2678 LEAVE_GL();
2680 if(!(This->Flags & SFLAG_DONOTFREE)) {
2681 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2682 This->resource.allocatedMemory = NULL;
2683 } else {
2684 This->Flags |= SFLAG_GLDIRTY;
2687 return WINED3D_OK;
2692 if (Flags & DDBLT_COLORFILL) {
2693 /* This is easy to handle for the D3D Device... */
2694 DWORD color;
2695 IWineD3DSwapChainImpl *implSwapChain;
2697 TRACE("Colorfill\n");
2699 /* The color as given in the Blt function is in the format of the frame-buffer...
2700 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2702 if (This->resource.format == WINED3DFMT_P8) {
2703 if (This->palette) {
2704 color = ((0xFF000000) |
2705 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2706 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2707 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2708 } else {
2709 color = 0xFF000000;
2712 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2713 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2714 color = 0xFFFFFFFF;
2715 } else {
2716 color = ((0xFF000000) |
2717 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2718 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2719 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2722 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2723 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2724 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2726 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2727 color = DDBltFx->u5.dwFillColor;
2729 else {
2730 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2731 return WINED3DERR_INVALIDCALL;
2734 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2735 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2736 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2737 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2738 glDrawBuffer(GL_BACK);
2739 checkGLcall("glDrawBuffer(GL_BACK)");
2741 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2742 glDrawBuffer(GL_FRONT);
2743 checkGLcall("glDrawBuffer(GL_FRONT)");
2745 else {
2746 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2747 return WINED3DERR_INVALIDCALL;
2750 TRACE("(%p) executing Render Target override, color = %lx\n", This, color);
2752 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2753 1 /* Number of rectangles */,
2754 &rect,
2755 D3DCLEAR_TARGET,
2756 color,
2757 0.0 /* Z */,
2758 0 /* Stencil */);
2760 /* Restore the original draw buffer */
2761 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2762 glDrawBuffer(GL_BACK);
2763 vcheckGLcall("glDrawBuffer");
2766 return WINED3D_OK;
2769 /* Default: Fall back to the generic blt */
2770 return WINED3DERR_INVALIDCALL;
2773 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2774 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2775 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2776 TRACE("(%p)->(%p,%p,%p,%lx,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2777 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2779 /* Special cases for RenderTargets */
2780 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2781 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2782 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2785 /* For the rest call the X11 surface implementation.
2786 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2787 * other Blts are rather rare
2789 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2792 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2793 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2794 TRACE("(%p)->(%lx)\n", This, Flags);
2796 switch (Flags)
2798 case DDGBS_CANBLT:
2799 case DDGBS_ISBLTDONE:
2800 return DD_OK;
2802 default:
2803 return DDERR_INVALIDPARAMS;
2807 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2808 /* XXX: DDERR_INVALIDSURFACETYPE */
2810 TRACE("(%p)->(%08lx)\n",iface,Flags);
2811 switch (Flags) {
2812 case DDGFS_CANFLIP:
2813 case DDGFS_ISFLIPDONE:
2814 return DD_OK;
2816 default:
2817 return DDERR_INVALIDPARAMS;
2821 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2822 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2823 TRACE("(%p)\n", This);
2825 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2828 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2829 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2830 TRACE("(%p)\n", This);
2832 /* So far we don't lose anything :) */
2833 This->Flags &= ~SFLAG_LOST;
2834 return WINED3D_OK;
2837 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2838 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2839 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2840 TRACE("(%p)->(%ld, %ld, %p, %p, %08lx\n", iface, dstx, dsty, Source, rsrc, trans);
2842 /* Special cases for RenderTargets */
2843 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2844 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2846 RECT SrcRect, DstRect;
2847 DWORD Flags=0;
2849 if(rsrc) {
2850 SrcRect.left = rsrc->left;
2851 SrcRect.top= rsrc->top;
2852 SrcRect.bottom = rsrc->bottom;
2853 SrcRect.right = rsrc->right;
2854 } else {
2855 SrcRect.left = 0;
2856 SrcRect.top = 0;
2857 SrcRect.right = srcImpl->currentDesc.Width;
2858 SrcRect.bottom = srcImpl->currentDesc.Height;
2861 DstRect.left = dstx;
2862 DstRect.top=dsty;
2863 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2864 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2866 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt aswell */
2867 if(trans & DDBLTFAST_SRCCOLORKEY)
2868 Flags |= DDBLT_KEYSRC;
2869 if(trans & DDBLTFAST_DESTCOLORKEY)
2870 Flags |= DDBLT_KEYDEST;
2871 if(trans & DDBLTFAST_WAIT)
2872 Flags |= DDBLT_WAIT;
2873 if(trans & DDBLTFAST_DONOTWAIT)
2874 Flags |= DDBLT_DONOTWAIT;
2876 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2880 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2883 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2884 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2885 TRACE("(%p)->(%p)\n", This, Pal);
2887 *Pal = (IWineD3DPalette *) This->palette;
2888 return DD_OK;
2891 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2892 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2893 RGBQUAD col[256];
2894 IWineD3DPaletteImpl *pal = This->palette;
2895 unsigned int n;
2896 TRACE("(%p)\n", This);
2898 if(This->resource.format == WINED3DFMT_P8 ||
2899 This->resource.format == WINED3DFMT_A8P8)
2901 TRACE("Dirtifying surface\n");
2902 This->Flags |= SFLAG_DIRTY;
2905 if(This->Flags & SFLAG_DIBSECTION) {
2906 TRACE("(%p): Updating the hdc's palette\n", This);
2907 for (n=0; n<256; n++) {
2908 if(pal) {
2909 col[n].rgbRed = pal->palents[n].peRed;
2910 col[n].rgbGreen = pal->palents[n].peGreen;
2911 col[n].rgbBlue = pal->palents[n].peBlue;
2912 } else {
2913 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2914 /* Use the default device palette */
2915 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2916 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2917 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2919 col[n].rgbReserved = 0;
2921 SetDIBColorTable(This->hDC, 0, 256, col);
2924 return WINED3D_OK;
2927 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2928 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2929 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2930 TRACE("(%p)->(%p)\n", This, Pal);
2932 if(This->palette != NULL)
2933 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2934 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2936 if(PalImpl != NULL) {
2937 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2938 /* Set the device's main palette if the palette
2939 * wasn't a primary palette before
2941 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2942 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2943 unsigned int i;
2945 for(i=0; i < 256; i++) {
2946 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2950 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2953 This->palette = PalImpl;
2955 return IWineD3DSurface_RealizePalette(iface);
2958 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2959 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2960 TRACE("(%p)->(%08lx,%p)\n", This, Flags, CKey);
2962 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2963 FIXME(" colorkey value not supported (%08lx) !\n", Flags);
2964 return DDERR_INVALIDPARAMS;
2967 /* Dirtify the surface, but only if a key was changed */
2968 if(CKey) {
2969 switch (Flags & ~DDCKEY_COLORSPACE) {
2970 case DDCKEY_DESTBLT:
2971 This->DestBltCKey = *CKey;
2972 This->CKeyFlags |= DDSD_CKDESTBLT;
2973 break;
2975 case DDCKEY_DESTOVERLAY:
2976 This->DestOverlayCKey = *CKey;
2977 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2978 break;
2980 case DDCKEY_SRCOVERLAY:
2981 This->SrcOverlayCKey = *CKey;
2982 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2983 break;
2985 case DDCKEY_SRCBLT:
2986 This->SrcBltCKey = *CKey;
2987 This->CKeyFlags |= DDSD_CKSRCBLT;
2988 break;
2991 else {
2992 switch (Flags & ~DDCKEY_COLORSPACE) {
2993 case DDCKEY_DESTBLT:
2994 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2995 break;
2997 case DDCKEY_DESTOVERLAY:
2998 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2999 break;
3001 case DDCKEY_SRCOVERLAY:
3002 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
3003 break;
3005 case DDCKEY_SRCBLT:
3006 This->CKeyFlags &= ~DDSD_CKSRCBLT;
3007 break;
3011 return WINED3D_OK;
3014 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3015 /** Check against the maximum texture sizes supported by the video card **/
3016 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3018 TRACE("%p\n", This);
3019 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3020 /* one of three options
3021 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)
3022 2: Set the texture to the maxium size (bad idea)
3023 3: WARN and return WINED3DERR_NOTAVAILABLE;
3024 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.
3026 WARN("(%p) Creating an oversized surface\n", This);
3027 This->Flags |= SFLAG_OVERSIZE;
3029 /* This will be initialized on the first blt */
3030 This->glRect.left = 0;
3031 This->glRect.top = 0;
3032 This->glRect.right = 0;
3033 This->glRect.bottom = 0;
3034 } else {
3035 /* No oversize, gl rect is the full texture size */
3036 This->Flags &= ~SFLAG_OVERSIZE;
3037 This->glRect.left = 0;
3038 This->glRect.top = 0;
3039 This->glRect.right = This->pow2Width;
3040 This->glRect.bottom = This->pow2Height;
3043 return WINED3D_OK;
3046 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3047 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3048 DWORD ret;
3049 TRACE("(%p)\n", This);
3051 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3052 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3053 ie pitch = (width/4) * bytes per block */
3054 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3055 ret = (This->currentDesc.Width >> 2) << 3;
3056 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3057 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3058 ret = (This->currentDesc.Width >> 2) << 4;
3059 else {
3060 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3061 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3062 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3063 } else {
3064 ret = This->bytesPerPixel * This->pow2Width;
3067 TRACE("(%p) Returning %ld\n", This, ret);
3068 return ret;
3071 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3073 /* IUnknown */
3074 IWineD3DSurfaceImpl_QueryInterface,
3075 IWineD3DSurfaceImpl_AddRef,
3076 IWineD3DSurfaceImpl_Release,
3077 /* IWineD3DResource */
3078 IWineD3DSurfaceImpl_GetParent,
3079 IWineD3DSurfaceImpl_GetDevice,
3080 IWineD3DSurfaceImpl_SetPrivateData,
3081 IWineD3DSurfaceImpl_GetPrivateData,
3082 IWineD3DSurfaceImpl_FreePrivateData,
3083 IWineD3DSurfaceImpl_SetPriority,
3084 IWineD3DSurfaceImpl_GetPriority,
3085 IWineD3DSurfaceImpl_PreLoad,
3086 IWineD3DSurfaceImpl_GetType,
3087 /* IWineD3DSurface */
3088 IWineD3DSurfaceImpl_GetContainerParent,
3089 IWineD3DSurfaceImpl_GetContainer,
3090 IWineD3DSurfaceImpl_GetDesc,
3091 IWineD3DSurfaceImpl_LockRect,
3092 IWineD3DSurfaceImpl_UnlockRect,
3093 IWineD3DSurfaceImpl_GetDC,
3094 IWineD3DSurfaceImpl_ReleaseDC,
3095 IWineD3DSurfaceImpl_Flip,
3096 IWineD3DSurfaceImpl_Blt,
3097 IWineD3DSurfaceImpl_GetBltStatus,
3098 IWineD3DSurfaceImpl_GetFlipStatus,
3099 IWineD3DSurfaceImpl_IsLost,
3100 IWineD3DSurfaceImpl_Restore,
3101 IWineD3DSurfaceImpl_BltFast,
3102 IWineD3DSurfaceImpl_GetPalette,
3103 IWineD3DSurfaceImpl_SetPalette,
3104 IWineD3DSurfaceImpl_RealizePalette,
3105 IWineD3DSurfaceImpl_SetColorKey,
3106 IWineD3DSurfaceImpl_GetPitch,
3107 IWineD3DSurfaceImpl_SetMem,
3108 /* Internal use: */
3109 IWineD3DSurfaceImpl_CleanDirtyRect,
3110 IWineD3DSurfaceImpl_AddDirtyRect,
3111 IWineD3DSurfaceImpl_LoadTexture,
3112 IWineD3DSurfaceImpl_SaveSnapshot,
3113 IWineD3DSurfaceImpl_SetContainer,
3114 IWineD3DSurfaceImpl_SetPBufferState,
3115 IWineD3DSurfaceImpl_SetGlTextureDesc,
3116 IWineD3DSurfaceImpl_GetGlDesc,
3117 IWineD3DSurfaceImpl_GetData,
3118 IWineD3DSurfaceImpl_SetFormat,
3119 IWineD3DSurfaceImpl_PrivateSetup