wined3d: Use SURFACE_ALIGNMENT.
[wine/hacks.git] / dlls / wined3d / surface.c
blob7fd300f5dd31718a763da93078e36542000e2e8a
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, UINT pitch, UINT height, UINT outpitch, 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 %d\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 %d\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(%08x), 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(%08x), 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(%08x), 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(%08x), 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(%08x), 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 %d, t %d, r %d, b %d\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
609 } else {
610 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\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 == WINED3DFMT_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,
994 height,
995 pitch * 4,
996 CONVERT_PALETTED,
997 This);
999 break;
1001 default:
1002 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
1004 /* Give it a try */
1005 type = This->glDescription.glType;
1006 fmt = This->glDescription.glFormat;
1007 mem = This->resource.allocatedMemory;
1010 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1011 (This->lockedRect.bottom - This->lockedRect.top)-1,
1012 fmt, type,
1013 mem);
1014 checkGLcall("glDrawPixels");
1015 glPixelZoom(1.0,1.0);
1016 vcheckGLcall("glPixelZoom");
1018 glRasterPos3iv(&prev_rasterpos[0]);
1019 vcheckGLcall("glRasterPos3iv");
1021 /* Reset to previous pack row length */
1022 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1023 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1024 if(storechanged) {
1025 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
1026 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1029 if(mem != This->resource.allocatedMemory) HeapFree(GetProcessHeap(), 0, mem);
1030 return;
1033 static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
1034 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1035 float glTexCoord[4];
1037 glTexCoord[0] = 0.0; /* left */
1038 glTexCoord[1] = (float) This->currentDesc.Width / (float) This->pow2Width; /* right */
1039 glTexCoord[2] = 0.0; /* top */
1040 glTexCoord[3] = (float) This->currentDesc.Height / (float) This->pow2Height; /* bottom */
1042 IWineD3DSurface_PreLoad(iface);
1044 ENTER_GL();
1046 /* Disable some fancy graphics effects */
1047 glDisable(GL_LIGHTING);
1048 checkGLcall("glDisable GL_LIGHTING");
1049 glDisable(GL_DEPTH_TEST);
1050 checkGLcall("glDisable GL_DEPTH_TEST");
1051 glDisable(GL_FOG);
1052 checkGLcall("glDisable GL_FOG");
1053 glDisable(GL_CULL_FACE);
1054 checkGLcall("glDisable GL_CULL_FACE");
1055 glDisable(GL_BLEND);
1056 checkGLcall("glDisable GL_BLEND");
1057 glDisable(GL_STENCIL_TEST);
1058 checkGLcall("glDisable GL_STENCIL_TEST");
1060 glEnable(GL_TEXTURE_2D);
1061 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1062 checkGLcall("glEnable glBindTexture");
1064 /* No filtering for blts */
1065 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1066 checkGLcall("glTexParameteri");
1067 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1068 checkGLcall("glTexParameteri");
1070 /* Start drawing a quad */
1071 glBegin(GL_QUADS);
1073 glColor3d(1.0f, 1.0f, 1.0f);
1074 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1075 glVertex3f(0, 0, 0.0);
1077 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1078 glVertex3f(0, This->currentDesc.Height, 0.0);
1080 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1081 glVertex3d(This->currentDesc.Width, This->currentDesc.Height, 0.0);
1083 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1084 glVertex3f(This->currentDesc.Width, 0, 0.0);
1086 glEnd();
1087 checkGLcall("glEnd");
1089 /* Unbind the texture */
1090 glBindTexture(GL_TEXTURE_2D, 0);
1091 checkGLcall("glEnable glBindTexture");
1093 LEAVE_GL();
1096 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1097 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1098 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1099 const char *buffername = "";
1100 IWineD3DSwapChainImpl *swapchain = NULL;
1101 BOOL backbuf = FALSE;
1103 if (!(This->Flags & SFLAG_LOCKED)) {
1104 WARN("trying to Unlock an unlocked surf@%p\n", This);
1105 return WINED3DERR_INVALIDCALL;
1108 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
1109 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1111 if(swapchain) {
1112 int i;
1113 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
1114 if(iface == swapchain->backBuffer[i]) {
1115 backbuf = TRUE;
1116 break;
1121 if (backbuf) {
1122 buffername = "backBuffer";
1123 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
1124 buffername = "frontBuffer";
1125 } else if (iface == myDevice->depthStencilBuffer) {
1126 buffername = "depthStencilBuffer";
1127 } else if (iface == myDevice->renderTarget) {
1128 buffername = "renderTarget";
1132 if (swapchain != NULL) {
1133 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1136 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
1138 if (!(This->Flags & SFLAG_DIRTY)) {
1139 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1140 goto unlock_end;
1143 if (0 == This->resource.usage) { /* classic surface */
1145 * nothing to do
1146 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
1148 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
1150 /****************************
1151 * TODO: Render targets are 'special' and
1152 * ?some? locking needs to be passed onto the context manager
1153 * so that it becomes possible to use auxiliary buffers, pbuffers
1154 * render-to-texture, shared, cached contexts etc...
1155 * ****************************/
1156 IWineD3DSwapChainImpl *implSwapChain;
1157 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
1159 if (backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->renderTarget) {
1160 int tex;
1162 ENTER_GL();
1164 /* glDrawPixels transforms the raster position as though it was a vertex -
1165 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1166 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1167 d3ddevice_set_ortho(This->resource.wineD3DDevice);
1169 if (iface == implSwapChain->frontBuffer) {
1170 glDrawBuffer(GL_FRONT);
1171 checkGLcall("glDrawBuffer GL_FRONT");
1172 } else if (backbuf || iface == myDevice->renderTarget) {
1173 glDrawBuffer(GL_BACK);
1174 checkGLcall("glDrawBuffer GL_BACK");
1177 /* Disable higher textures before calling glDrawPixels */
1178 for(tex = 1; tex < GL_LIMITS(samplers); tex++) {
1179 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1180 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + tex));
1181 checkGLcall("glActiveTextureARB");
1183 glDisable(GL_TEXTURE_2D);
1184 checkGLcall("glDisable GL_TEXTURE_2D");
1185 glDisable(GL_TEXTURE_1D);
1186 checkGLcall("glDisable GL_TEXTURE_1D");
1188 /* Activate texture 0, but don't disable it necessarilly */
1189 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1190 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1191 checkGLcall("glActiveTextureARB");
1194 /* And back buffers are not blended. Disable the depth test,
1195 that helps performance */
1196 glDisable(GL_BLEND);
1197 glDisable(GL_DEPTH_TEST);
1198 glDisable(GL_FOG);
1200 switch(wined3d_settings.rendertargetlock_mode) {
1201 case RTL_AUTO:
1202 case RTL_READDRAW:
1203 case RTL_TEXDRAW:
1204 flush_to_framebuffer_drawpixels(This);
1205 break;
1207 case RTL_READTEX:
1208 case RTL_TEXTEX:
1209 flush_to_framebuffer_texture(iface);
1210 break;
1212 case RTL_DISABLE:
1214 static BOOL warned = FALSE;
1215 if(!warned) {
1216 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1217 warned = TRUE;
1220 break;
1223 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1224 glDrawBuffer(GL_BACK);
1225 vcheckGLcall("glDrawBuffer");
1227 if(myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_TRUE ||
1228 myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_USEW) glEnable(GL_DEPTH_TEST);
1229 if (myDevice->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1230 if (myDevice->stateBlock->renderState[WINED3DRS_FOGENABLE]) glEnable(GL_FOG);
1232 LEAVE_GL();
1234 /** restore clean dirty state */
1235 IWineD3DSurface_CleanDirtyRect(iface);
1237 } else {
1238 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1240 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1242 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1244 if (iface == myDevice->depthStencilBuffer) {
1245 FIXME("TODO stencil depth surface unlocking surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1246 } else {
1247 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1250 } else {
1251 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1254 unlock_end:
1255 This->Flags &= ~SFLAG_LOCKED;
1256 memset(&This->lockedRect, 0, sizeof(RECT));
1257 return WINED3D_OK;
1260 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1261 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1262 WINED3DLOCKED_RECT lock;
1263 UINT usage;
1264 BITMAPINFO* b_info;
1265 HDC ddc;
1266 DWORD *masks;
1267 HRESULT hr;
1268 RGBQUAD col[256];
1269 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1271 TRACE("(%p)->(%p)\n",This,pHDC);
1273 if(This->Flags & SFLAG_USERPTR) {
1274 ERR("Not supported on surfaces with an application-provided surfaces\n");
1275 return DDERR_NODC;
1278 /* Give more detailed info for ddraw */
1279 if (This->Flags & SFLAG_DCINUSE)
1280 return DDERR_DCALREADYCREATED;
1282 /* Can't GetDC if the surface is locked */
1283 if (This->Flags & SFLAG_LOCKED)
1284 return WINED3DERR_INVALIDCALL;
1286 memset(&lock, 0, sizeof(lock)); /* To be sure */
1288 /* Create a DIB section if there isn't a hdc yet */
1289 if(!This->hDC) {
1290 int extraline = 0;
1291 SYSTEM_INFO sysInfo;
1293 if(This->Flags & SFLAG_ACTIVELOCK) {
1294 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1297 switch (This->bytesPerPixel) {
1298 case 2:
1299 case 4:
1300 /* Allocate extra space to store the RGB bit masks. */
1301 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1302 break;
1304 case 3:
1305 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1306 break;
1308 default:
1309 /* Allocate extra space for a palette. */
1310 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1311 sizeof(BITMAPINFOHEADER)
1312 + sizeof(RGBQUAD)
1313 * (1 << (This->bytesPerPixel * 8)));
1314 break;
1317 if (!b_info)
1318 return E_OUTOFMEMORY;
1320 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1321 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1322 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1323 * add an extra line to the dib section
1325 GetSystemInfo(&sysInfo);
1326 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1327 extraline = 1;
1328 TRACE("Adding an extra line to the dib section\n");
1331 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1332 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1333 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1334 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1335 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1336 /* Use the full pow2 image size(assigned below) because LockRect
1337 * will need it for a full glGetTexImage call
1339 } else {
1340 b_info->bmiHeader.biWidth = This->pow2Width;
1341 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1342 b_info->bmiHeader.biSizeImage = This->resource.size + extraline * IWineD3DSurface_GetPitch(iface);
1344 b_info->bmiHeader.biPlanes = 1;
1345 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1347 b_info->bmiHeader.biXPelsPerMeter = 0;
1348 b_info->bmiHeader.biYPelsPerMeter = 0;
1349 b_info->bmiHeader.biClrUsed = 0;
1350 b_info->bmiHeader.biClrImportant = 0;
1352 /* Get the bit masks */
1353 masks = (DWORD *) &(b_info->bmiColors);
1354 switch (This->resource.format) {
1355 case WINED3DFMT_R8G8B8:
1356 usage = DIB_RGB_COLORS;
1357 b_info->bmiHeader.biCompression = BI_RGB;
1358 break;
1360 case WINED3DFMT_X1R5G5B5:
1361 case WINED3DFMT_A1R5G5B5:
1362 case WINED3DFMT_A4R4G4B4:
1363 case WINED3DFMT_X4R4G4B4:
1364 case WINED3DFMT_R3G3B2:
1365 case WINED3DFMT_A8R3G3B2:
1366 case WINED3DFMT_A2B10G10R10:
1367 case WINED3DFMT_A8B8G8R8:
1368 case WINED3DFMT_X8B8G8R8:
1369 case WINED3DFMT_A2R10G10B10:
1370 case WINED3DFMT_R5G6B5:
1371 case WINED3DFMT_A16B16G16R16:
1372 usage = 0;
1373 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1374 masks[0] = formatEntry->redMask;
1375 masks[1] = formatEntry->greenMask;
1376 masks[2] = formatEntry->blueMask;
1377 break;
1379 default:
1380 /* Don't know palette */
1381 b_info->bmiHeader.biCompression = BI_RGB;
1382 usage = 0;
1383 break;
1386 ddc = CreateDCA("DISPLAY", NULL, NULL, NULL);
1387 if (ddc == 0) {
1388 HeapFree(GetProcessHeap(), 0, b_info);
1389 return HRESULT_FROM_WIN32(GetLastError());
1392 TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
1393 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1394 DeleteDC(ddc);
1396 if (!This->dib.DIBsection) {
1397 ERR("CreateDIBSection failed!\n");
1398 HeapFree(GetProcessHeap(), 0, b_info);
1399 return HRESULT_FROM_WIN32(GetLastError());
1402 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1404 /* copy the existing surface to the dib section */
1405 if(This->resource.allocatedMemory) {
1406 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1407 /* We won't need that any more */
1408 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1409 } else {
1410 /* This is to make LockRect read the gl Texture although memory is allocated */
1411 This->Flags |= SFLAG_GLDIRTY;
1414 HeapFree(GetProcessHeap(), 0, b_info);
1416 /* Use the dib section from now on */
1417 This->resource.allocatedMemory = This->dib.bitmap_data;
1419 /* Now allocate a HDC */
1420 This->hDC = CreateCompatibleDC(0);
1421 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1422 TRACE("using wined3d palette %p\n", This->palette);
1423 SelectPalette(This->hDC,
1424 This->palette ? This->palette->hpal : 0,
1425 FALSE);
1427 This->Flags |= SFLAG_DIBSECTION;
1430 /* Lock the surface */
1431 hr = IWineD3DSurface_LockRect(iface,
1432 &lock,
1433 NULL,
1435 if(FAILED(hr)) {
1436 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1437 /* keep the dib section */
1438 return hr;
1441 if(This->resource.format == WINED3DFMT_P8 ||
1442 This->resource.format == WINED3DFMT_A8P8) {
1443 unsigned int n;
1444 if(This->palette) {
1445 PALETTEENTRY ent[256];
1447 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1448 for (n=0; n<256; n++) {
1449 col[n].rgbRed = ent[n].peRed;
1450 col[n].rgbGreen = ent[n].peGreen;
1451 col[n].rgbBlue = ent[n].peBlue;
1452 col[n].rgbReserved = 0;
1454 } else {
1455 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1457 for (n=0; n<256; n++) {
1458 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1459 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1460 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1461 col[n].rgbReserved = 0;
1465 SetDIBColorTable(This->hDC, 0, 256, col);
1468 *pHDC = This->hDC;
1469 TRACE("returning %p\n",*pHDC);
1470 This->Flags |= SFLAG_DCINUSE;
1472 return WINED3D_OK;
1475 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1476 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1478 TRACE("(%p)->(%p)\n",This,hDC);
1480 if (!(This->Flags & SFLAG_DCINUSE))
1481 return D3DERR_INVALIDCALL;
1483 /* we locked first, so unlock now */
1484 IWineD3DSurface_UnlockRect(iface);
1486 This->Flags &= ~SFLAG_DCINUSE;
1488 return WINED3D_OK;
1491 /* ******************************************************
1492 IWineD3DSurface Internal (No mapping to directx api) parts follow
1493 ****************************************************** */
1495 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) {
1496 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1497 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1499 /* Default values: From the surface */
1500 *format = formatEntry->glFormat;
1501 *internal = formatEntry->glInternal;
1502 *type = formatEntry->glType;
1503 *convert = NO_CONVERSION;
1504 *target_bpp = This->bytesPerPixel;
1506 /* Ok, now look if we have to do any conversion */
1507 switch(This->resource.format) {
1508 case WINED3DFMT_P8:
1509 /* ****************
1510 Paletted Texture
1511 **************** */
1512 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1513 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1515 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1516 *format = GL_RGBA;
1517 *internal = GL_RGBA;
1518 *type = GL_UNSIGNED_BYTE;
1519 *target_bpp = 4;
1520 if(colorkey_active) {
1521 *convert = CONVERT_PALETTED_CK;
1522 } else {
1523 *convert = CONVERT_PALETTED;
1527 break;
1529 case WINED3DFMT_R3G3B2:
1530 /* **********************
1531 GL_UNSIGNED_BYTE_3_3_2
1532 ********************** */
1533 if (colorkey_active) {
1534 /* This texture format will never be used.. So do not care about color keying
1535 up until the point in time it will be needed :-) */
1536 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1538 break;
1540 case WINED3DFMT_R5G6B5:
1541 if (colorkey_active) {
1542 *convert = CONVERT_CK_565;
1543 *format = GL_RGBA;
1544 *internal = GL_RGBA;
1545 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1547 break;
1549 case WINED3DFMT_R8G8B8:
1550 if (colorkey_active) {
1551 *convert = CONVERT_CK_RGB24;
1552 *format = GL_RGBA;
1553 *internal = GL_RGBA;
1554 *type = GL_UNSIGNED_INT_8_8_8_8;
1555 *target_bpp = 4;
1557 break;
1559 case WINED3DFMT_X8R8G8B8:
1560 if (colorkey_active) {
1561 *convert = CONVERT_RGB32_888;
1562 *format = GL_RGBA;
1563 *internal = GL_RGBA;
1564 *type = GL_UNSIGNED_INT_8_8_8_8;
1566 break;
1568 default:
1569 break;
1572 return WINED3D_OK;
1575 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1576 BYTE *dest;
1577 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1579 switch (convert) {
1580 case NO_CONVERSION:
1582 memcpy(dst, src, pitch * height);
1583 break;
1585 case CONVERT_PALETTED:
1586 case CONVERT_PALETTED_CK:
1588 IWineD3DPaletteImpl* pal = surf->palette;
1589 BYTE table[256][4];
1590 unsigned int i;
1591 unsigned int x, y;
1593 if( pal == NULL) {
1594 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1597 if (pal == NULL) {
1598 /* Still no palette? Use the device's palette */
1599 /* Get the surface's palette */
1600 for (i = 0; i < 256; i++) {
1601 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1603 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1604 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1605 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1606 if ((convert == CONVERT_PALETTED_CK) &&
1607 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1608 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1609 /* We should maybe here put a more 'neutral' color than the standard bright purple
1610 one often used by application to prevent the nice purple borders when bi-linear
1611 filtering is on */
1612 table[i][3] = 0x00;
1613 } else {
1614 table[i][3] = 0xFF;
1617 } else {
1618 TRACE("Using surface palette %p\n", pal);
1619 /* Get the surface's palette */
1620 for (i = 0; i < 256; i++) {
1621 table[i][0] = pal->palents[i].peRed;
1622 table[i][1] = pal->palents[i].peGreen;
1623 table[i][2] = pal->palents[i].peBlue;
1624 if ((convert == CONVERT_PALETTED_CK) &&
1625 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1626 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1627 /* We should maybe here put a more 'neutral' color than the standard bright purple
1628 one often used by application to prevent the nice purple borders when bi-linear
1629 filtering is on */
1630 table[i][3] = 0x00;
1631 } else {
1632 table[i][3] = 0xFF;
1637 for (y = 0; y < height; y++)
1639 dest = dst + outpitch * y;
1640 /* This is an 1 bpp format, using the pitch here is fine */
1641 for (x = 0; x < pitch; x++) {
1642 BYTE color = *src++;
1643 *dest++ = table[color][0];
1644 *dest++ = table[color][1];
1645 *dest++ = table[color][2];
1646 *dest++ = table[color][3];
1650 break;
1652 case CONVERT_CK_565:
1654 /* Converting the 565 format in 5551 packed to emulate color-keying.
1656 Note : in all these conversion, it would be best to average the averaging
1657 pixels to get the color of the pixel that will be color-keyed to
1658 prevent 'color bleeding'. This will be done later on if ever it is
1659 too visible.
1661 Note2: Nvidia documents say that their driver does not support alpha + color keying
1662 on the same surface and disables color keying in such a case
1664 unsigned int x, y;
1665 WORD *Source;
1666 WORD *Dest;
1668 TRACE("Color keyed 565\n");
1670 for (y = 0; y < height; y++) {
1671 Source = (WORD *) (src + y * pitch);
1672 Dest = (WORD *) (dst + y * outpitch);
1673 for (x = 0; x < pitch / 2; x++ ) {
1674 WORD color = *Source++;
1675 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1676 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1677 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1678 *Dest |= 0x0001;
1680 Dest++;
1684 break;
1686 default:
1687 ERR("Unsupported conversation type %d\n", convert);
1689 return WINED3D_OK;
1692 /* This function is used in case of 8bit paletted textures to upload the palette.
1693 For now it only supports GL_EXT_paletted_texture extension but support for other
1694 extensions like ARB_fragment_program and ATI_fragment_shaders will be added aswell.
1696 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1697 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1698 IWineD3DPaletteImpl* pal = This->palette;
1699 BYTE table[256][4];
1700 int i;
1702 if (pal == NULL) {
1703 /* Still no palette? Use the device's palette */
1704 /* Get the surface's palette */
1705 for (i = 0; i < 256; i++) {
1706 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1708 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1709 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1710 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1711 if ((convert == CONVERT_PALETTED_CK) &&
1712 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1713 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1714 /* We should maybe here put a more 'neutral' color than the standard bright purple
1715 one often used by application to prevent the nice purple borders when bi-linear
1716 filtering is on */
1717 table[i][3] = 0x00;
1718 } else {
1719 table[i][3] = 0xFF;
1722 } else {
1723 TRACE("Using surface palette %p\n", pal);
1724 /* Get the surface's palette */
1725 for (i = 0; i < 256; i++) {
1726 table[i][0] = pal->palents[i].peRed;
1727 table[i][1] = pal->palents[i].peGreen;
1728 table[i][2] = pal->palents[i].peBlue;
1729 if ((convert == CONVERT_PALETTED_CK) &&
1730 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1731 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1732 /* We should maybe here put a more 'neutral' color than the standard bright purple
1733 one often used by application to prevent the nice purple borders when bi-linear
1734 filtering is on */
1735 table[i][3] = 0x00;
1736 } else {
1737 table[i][3] = 0xFF;
1741 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1744 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1745 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1746 GLenum format, internal, type;
1747 CONVERT_TYPES convert;
1748 int bpp;
1749 int width, pitch, outpitch;
1750 BYTE *mem;
1752 if (This->Flags & SFLAG_INTEXTURE) {
1753 TRACE("Surface already in texture\n");
1754 return WINED3D_OK;
1756 if (This->Flags & SFLAG_DIRTY) {
1757 TRACE("Reloading because surface is dirty\n");
1758 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1759 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1760 /* Reload: vice versa OR */
1761 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1762 /* Also reload: Color key is active AND the color key has changed */
1763 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1764 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1765 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1766 TRACE("Reloading because of color keying\n");
1767 } else {
1768 TRACE("surface isn't dirty\n");
1769 return WINED3D_OK;
1772 This->Flags &= ~SFLAG_DIRTY;
1774 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1775 * These resources are not bound by device size or format restrictions. Because of this,
1776 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1777 * However, these resources can always be created, locked, and copied.
1779 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1781 FIXME("(%p) Operation not supported for scratch textures\n",This);
1782 return WINED3DERR_INVALIDCALL;
1785 if (This->Flags & SFLAG_INPBUFFER) {
1786 if (This->glDescription.level != 0)
1787 FIXME("Surface in texture is only supported for level 0\n");
1788 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1789 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1790 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1791 This->resource.format == WINED3DFMT_DXT5)
1792 FIXME("Format %d not supported\n", This->resource.format);
1793 else {
1794 GLint prevRead;
1796 ENTER_GL();
1798 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1799 vcheckGLcall("glGetIntegerv");
1800 glReadBuffer(GL_BACK);
1801 vcheckGLcall("glReadBuffer");
1803 glCopyTexImage2D(This->glDescription.target,
1804 This->glDescription.level,
1805 This->glDescription.glFormatInternal,
1808 This->currentDesc.Width,
1809 This->currentDesc.Height,
1812 checkGLcall("glCopyTexImage2D");
1813 glReadBuffer(prevRead);
1814 vcheckGLcall("glReadBuffer");
1816 LEAVE_GL();
1818 TRACE("Updating target %d\n", This->glDescription.target);
1819 This->Flags |= SFLAG_INTEXTURE;
1821 return WINED3D_OK;
1824 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1825 This->Flags |= SFLAG_GLCKEY;
1826 This->glCKey = This->SrcBltCKey;
1828 else This->Flags &= ~SFLAG_GLCKEY;
1830 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1832 /* The width is in 'length' not in bytes */
1833 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1834 width = This->currentDesc.Width;
1835 else
1836 width = This->pow2Width;
1838 pitch = IWineD3DSurface_GetPitch(iface);
1840 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1841 int height = This->glRect.bottom - This->glRect.top;
1843 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1844 outpitch = width * bpp;
1845 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1847 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1848 if(!mem) {
1849 ERR("Out of memory %d, %d!\n", outpitch, height);
1850 return WINED3DERR_OUTOFVIDEOMEMORY;
1852 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, height, outpitch, convert, This);
1854 This->Flags |= SFLAG_CONVERTED;
1855 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1856 d3dfmt_p8_upload_palette(iface, convert);
1857 This->Flags &= ~SFLAG_CONVERTED;
1858 mem = This->resource.allocatedMemory;
1859 } else {
1860 This->Flags &= ~SFLAG_CONVERTED;
1861 mem = This->resource.allocatedMemory;
1864 /* Make sure the correct pitch is used */
1865 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1867 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1868 TRACE("non power of two support\n");
1869 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1870 if (mem) {
1871 surface_upload_data(This, This->pow2Width, This->pow2Height, format, type, mem);
1873 } else {
1874 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1875 if (mem) {
1876 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1880 /* Restore the default pitch */
1881 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1883 if (mem != This->resource.allocatedMemory)
1884 HeapFree(GetProcessHeap(), 0, mem);
1886 #if 0
1888 static unsigned int gen = 0;
1889 char buffer[4096];
1890 ++gen;
1891 if ((gen % 10) == 0) {
1892 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1893 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1896 * debugging crash code
1897 if (gen == 250) {
1898 void** test = NULL;
1899 *test = 0;
1903 #endif
1905 if (!(This->Flags & SFLAG_DONOTFREE)) {
1906 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1907 This->resource.allocatedMemory = NULL;
1910 return WINED3D_OK;
1913 #include <errno.h>
1914 #include <stdio.h>
1915 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1916 FILE* f = NULL;
1917 UINT i, y;
1918 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1919 char *allocatedMemory;
1920 char *textureRow;
1921 IWineD3DSwapChain *swapChain = NULL;
1922 int width, height;
1923 GLuint tmpTexture = 0;
1924 DWORD color;
1925 /*FIXME:
1926 Textures my not be stored in ->allocatedgMemory and a GlTexture
1927 so we should lock the surface before saving a snapshot, or at least check that
1929 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1930 by calling GetTexImage and in compressed form by calling
1931 GetCompressedTexImageARB. Queried compressed images can be saved and
1932 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1933 texture images do not need to be processed by the GL and should
1934 significantly improve texture loading performance relative to uncompressed
1935 images. */
1937 /* Setup the width and height to be the internal texture width and height. */
1938 width = This->pow2Width;
1939 height = This->pow2Height;
1940 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1941 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1943 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1944 /* 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 */
1945 GLint prevRead;
1946 ENTER_GL();
1947 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1948 glEnable(GL_TEXTURE_2D);
1950 glGenTextures(1, &tmpTexture);
1951 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1953 glTexImage2D(GL_TEXTURE_2D,
1955 GL_RGBA,
1956 width,
1957 height,
1958 0/*border*/,
1959 GL_RGBA,
1960 GL_UNSIGNED_INT_8_8_8_8_REV,
1961 NULL);
1963 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1964 vcheckGLcall("glGetIntegerv");
1965 glReadBuffer(GL_BACK);
1966 vcheckGLcall("glReadBuffer");
1967 glCopyTexImage2D(GL_TEXTURE_2D,
1969 GL_RGBA,
1972 width,
1973 height,
1976 checkGLcall("glCopyTexImage2D");
1977 glReadBuffer(prevRead);
1978 LEAVE_GL();
1980 } else { /* bind the real texture */
1981 IWineD3DSurface_PreLoad(iface);
1983 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1984 ENTER_GL();
1985 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1986 glGetTexImage(GL_TEXTURE_2D,
1987 This->glDescription.level,
1988 GL_RGBA,
1989 GL_UNSIGNED_INT_8_8_8_8_REV,
1990 allocatedMemory);
1991 checkGLcall("glTexImage2D");
1992 if (tmpTexture) {
1993 glBindTexture(GL_TEXTURE_2D, 0);
1994 glDeleteTextures(1, &tmpTexture);
1996 LEAVE_GL();
1998 f = fopen(filename, "w+");
1999 if (NULL == f) {
2000 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2001 return WINED3DERR_INVALIDCALL;
2003 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
2004 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2005 /* TGA header */
2006 fputc(0,f);
2007 fputc(0,f);
2008 fputc(2,f);
2009 fputc(0,f);
2010 fputc(0,f);
2011 fputc(0,f);
2012 fputc(0,f);
2013 fputc(0,f);
2014 fputc(0,f);
2015 fputc(0,f);
2016 fputc(0,f);
2017 fputc(0,f);
2018 /* short width*/
2019 fwrite(&width,2,1,f);
2020 /* short height */
2021 fwrite(&height,2,1,f);
2022 /* format rgba */
2023 fputc(0x20,f);
2024 fputc(0x28,f);
2025 /* raw data */
2026 /* 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*/
2027 if(swapChain)
2028 textureRow = allocatedMemory + (width * (height - 1) *4);
2029 else
2030 textureRow = allocatedMemory;
2031 for (y = 0 ; y < height; y++) {
2032 for (i = 0; i < width; i++) {
2033 color = *((DWORD*)textureRow);
2034 fputc((color >> 16) & 0xFF, f); /* B */
2035 fputc((color >> 8) & 0xFF, f); /* G */
2036 fputc((color >> 0) & 0xFF, f); /* R */
2037 fputc((color >> 24) & 0xFF, f); /* A */
2038 textureRow += 4;
2040 /* take two rows of the pointer to the texture memory */
2041 if(swapChain)
2042 (textureRow-= width << 3);
2045 TRACE("Closing file\n");
2046 fclose(f);
2048 if(swapChain) {
2049 IWineD3DSwapChain_Release(swapChain);
2051 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2052 return WINED3D_OK;
2055 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2056 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2057 This->Flags &= ~SFLAG_DIRTY;
2058 This->dirtyRect.left = This->currentDesc.Width;
2059 This->dirtyRect.top = This->currentDesc.Height;
2060 This->dirtyRect.right = 0;
2061 This->dirtyRect.bottom = 0;
2062 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2063 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2064 return WINED3D_OK;
2068 * Slightly inefficient way to handle multiple dirty rects but it works :)
2070 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2071 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2072 IWineD3DBaseTexture *baseTexture = NULL;
2073 This->Flags |= SFLAG_DIRTY;
2074 if (NULL != pDirtyRect) {
2075 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2076 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2077 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2078 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2079 } else {
2080 This->dirtyRect.left = 0;
2081 This->dirtyRect.top = 0;
2082 This->dirtyRect.right = This->currentDesc.Width;
2083 This->dirtyRect.bottom = This->currentDesc.Height;
2085 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2086 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2087 /* if the container is a basetexture then mark it dirty. */
2088 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2089 TRACE("Passing to conatiner\n");
2090 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2091 IWineD3DBaseTexture_Release(baseTexture);
2093 return WINED3D_OK;
2096 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2097 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2099 TRACE("This %p, container %p\n", This, container);
2101 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2103 TRACE("Setting container to %p from %p\n", container, This->container);
2104 This->container = container;
2106 return WINED3D_OK;
2109 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2110 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2111 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2113 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2114 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2115 return WINED3DERR_INVALIDCALL;
2118 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2119 if (format == WINED3DFMT_UNKNOWN) {
2120 This->resource.size = 0;
2121 } else if (format == WINED3DFMT_DXT1) {
2122 /* DXT1 is half byte per pixel */
2123 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2125 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2126 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2127 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2128 } else {
2129 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2130 This->resource.size *= This->pow2Height;
2134 /* Setup some glformat defaults */
2135 This->glDescription.glFormat = formatEntry->glFormat;
2136 This->glDescription.glFormatInternal = formatEntry->glInternal;
2137 This->glDescription.glType = formatEntry->glType;
2139 if (format != WINED3DFMT_UNKNOWN) {
2140 This->bytesPerPixel = formatEntry->bpp;
2141 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2142 } else {
2143 This->bytesPerPixel = 0;
2144 This->pow2Size = 0;
2147 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2149 This->resource.format = format;
2151 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);
2153 return WINED3D_OK;
2156 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2157 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2159 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2160 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2161 ERR("Not supported on render targets\n");
2162 return WINED3DERR_INVALIDCALL;
2165 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2166 WARN("Surface is locked or the HDC is in use\n");
2167 return WINED3DERR_INVALIDCALL;
2170 if(Mem && Mem != This->resource.allocatedMemory) {
2172 /* Do I have to copy the old surface content? */
2173 if(This->Flags & SFLAG_DIBSECTION) {
2174 /* Release the DC. No need to hold the critical section for the update
2175 * Thread because this thread runs only on front buffers, but this method
2176 * fails for render targets in the check above.
2178 SelectObject(This->hDC, This->dib.holdbitmap);
2179 DeleteDC(This->hDC);
2180 /* Release the DIB section */
2181 DeleteObject(This->dib.DIBsection);
2182 This->dib.bitmap_data = NULL;
2183 This->resource.allocatedMemory = NULL;
2184 This->hDC = NULL;
2185 This->Flags &= ~SFLAG_DIBSECTION;
2186 } else if(!(This->Flags & SFLAG_USERPTR)) {
2187 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2189 This->resource.allocatedMemory = Mem;
2190 This->Flags |= SFLAG_USERPTR;
2191 } else if(This->Flags & SFLAG_USERPTR) {
2192 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2193 This->resource.allocatedMemory = NULL;
2194 This->Flags &= ~SFLAG_USERPTR;
2196 return WINED3D_OK;
2199 /* TODO: replace this function with context management routines */
2200 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2201 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2203 if(inPBuffer) {
2204 This->Flags |= SFLAG_INPBUFFER;
2205 } else {
2206 This->Flags &= ~SFLAG_INPBUFFER;
2209 if(inTexture) {
2210 This->Flags |= SFLAG_INTEXTURE;
2211 } else {
2212 This->Flags &= ~SFLAG_INTEXTURE;
2215 return WINED3D_OK;
2218 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2219 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2220 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2221 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2223 /* Flipping is only supported on RenderTargets */
2224 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2226 if(override) {
2227 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2228 * FIXME("(%p) Target override is not supported by now\n", This);
2229 * Additionally, it isn't really possible to support triple-buffering
2230 * properly on opengl at all
2234 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2235 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2238 /* Not called from the VTable */
2239 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2240 WINED3DRECT rect;
2241 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2242 IWineD3DSwapChainImpl *swapchain = NULL;
2243 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2244 BOOL SrcOK = TRUE;
2246 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2248 /* Get the swapchain. One of the surfaces has to be a primary surface */
2249 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2250 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2251 else if(Src) {
2252 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2253 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2254 else return WINED3DERR_INVALIDCALL;
2255 } else {
2256 swapchain = NULL;
2259 if (DestRect) {
2260 rect.x1 = DestRect->left;
2261 rect.y1 = DestRect->top;
2262 rect.x2 = DestRect->right;
2263 rect.y2 = DestRect->bottom;
2264 } else {
2265 rect.x1 = 0;
2266 rect.y1 = 0;
2267 rect.x2 = This->currentDesc.Width;
2268 rect.y2 = This->currentDesc.Height;
2271 /* Half-life does a Blt from the back buffer to the front buffer,
2272 * Full surface size, no flags... Use present instead
2274 if(Src)
2276 /* First, check if we can do a Flip */
2278 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2279 if( SrcRect ) {
2280 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2281 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2282 SrcOK = TRUE;
2284 } else {
2285 SrcOK = TRUE;
2288 /* Check the Destination rect and the surface sizes */
2289 if(SrcOK &&
2290 (rect.x1 == 0) && (rect.y1 == 0) &&
2291 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2292 (This->currentDesc.Width == Src->currentDesc.Width) &&
2293 (This->currentDesc.Height == Src->currentDesc.Height)) {
2294 /* These flags are unimportant for the flag check, remove them */
2296 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2297 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2299 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2301 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2302 * take very long, while a flip is fast.
2303 * This applies to Half-Life, which does such Blts every time it finished
2304 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2305 * menu. This is also used by all apps when they do windowed rendering
2307 * The problem is that flipping is not really the same as copying. After a
2308 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2309 * untouched. Therefore it's necessary to override the swap effect
2310 * and to set it back after the flip.
2313 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2315 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2316 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2317 NULL, NULL, 0, NULL);
2319 swapchain->presentParms.SwapEffect = orig_swap;
2321 return WINED3D_OK;
2326 /* Blt from texture to rendertarget? */
2327 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2328 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2330 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2331 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2332 float glTexCoord[4];
2333 DWORD oldCKey;
2334 DDCOLORKEY oldBltCKey = {0,0};
2335 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2336 GLint oldStencil, oldNVRegisterCombiners = 0;
2337 GLint alphafunc;
2338 GLclampf alpharef;
2339 RECT SourceRectangle;
2340 GLint oldDraw;
2342 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2344 if(SrcRect) {
2345 SourceRectangle.left = SrcRect->left;
2346 SourceRectangle.right = SrcRect->right;
2347 SourceRectangle.top = SrcRect->top;
2348 SourceRectangle.bottom = SrcRect->bottom;
2349 } else {
2350 SourceRectangle.left = 0;
2351 SourceRectangle.right = Src->currentDesc.Width;
2352 SourceRectangle.top = 0;
2353 SourceRectangle.bottom = Src->currentDesc.Height;
2356 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2357 /* Fall back to software */
2358 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2359 SourceRectangle.left, SourceRectangle.top,
2360 SourceRectangle.right, SourceRectangle.bottom);
2361 return WINED3DERR_INVALIDCALL;
2364 /* Color keying: Check if we have to do a color keyed blt,
2365 * and if not check if a color key is activated.
2367 oldCKey = Src->CKeyFlags;
2368 if(!(Flags & DDBLT_KEYSRC) &&
2369 Src->CKeyFlags & DDSD_CKSRCBLT) {
2370 /* Ok, the surface has a color key, but we shall not use it -
2371 * Deactivate it for now, LoadTexture will catch this
2373 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2376 /* Color keying */
2377 if(Flags & DDBLT_KEYDEST) {
2378 oldBltCKey = This->SrcBltCKey;
2379 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2380 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2382 This->SrcBltCKey = This->DestBltCKey;
2383 } else if (Flags & DDBLT_KEYSRC)
2384 oldBltCKey = This->SrcBltCKey;
2386 /* Now load the surface */
2387 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2389 ENTER_GL();
2391 /* Save all the old stuff until we have a proper opengl state manager */
2392 oldLight = glIsEnabled(GL_LIGHTING);
2393 oldFog = glIsEnabled(GL_FOG);
2394 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2395 oldBlend = glIsEnabled(GL_BLEND);
2396 oldCull = glIsEnabled(GL_CULL_FACE);
2397 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2398 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2400 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2401 oldNVRegisterCombiners = glIsEnabled(GL_REGISTER_COMBINERS_NV);
2404 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2405 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2406 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2407 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2409 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2410 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2411 TRACE("Drawing to front buffer\n");
2412 glDrawBuffer(GL_FRONT);
2413 checkGLcall("glDrawBuffer GL_FRONT");
2416 /* Unbind the old texture */
2417 glBindTexture(GL_TEXTURE_2D, 0);
2419 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2420 /* We use texture unit 0 for blts */
2421 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2422 checkGLcall("glActiveTextureARB");
2423 } else {
2424 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2427 /* Disable some fancy graphics effects */
2428 glDisable(GL_LIGHTING);
2429 checkGLcall("glDisable GL_LIGHTING");
2430 glDisable(GL_DEPTH_TEST);
2431 checkGLcall("glDisable GL_DEPTH_TEST");
2432 glDisable(GL_FOG);
2433 checkGLcall("glDisable GL_FOG");
2434 glDisable(GL_BLEND);
2435 checkGLcall("glDisable GL_BLEND");
2436 glDisable(GL_CULL_FACE);
2437 checkGLcall("glDisable GL_CULL_FACE");
2438 glDisable(GL_STENCIL_TEST);
2439 checkGLcall("glDisable GL_STENCIL_TEST");
2440 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2441 glDisable(GL_REGISTER_COMBINERS_NV);
2442 checkGLcall("glDisable GL_REGISTER_COMBINERS_NV");
2445 /* Ok, we need 2d textures, but not 1D or 3D */
2446 glDisable(GL_TEXTURE_1D);
2447 checkGLcall("glDisable GL_TEXTURE_1D");
2448 glEnable(GL_TEXTURE_2D);
2449 checkGLcall("glEnable GL_TEXTURE_2D");
2450 glDisable(GL_TEXTURE_3D);
2451 checkGLcall("glDisable GL_TEXTURE_3D");
2453 /* Bind the texture */
2454 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2455 checkGLcall("glBindTexture");
2457 glEnable(GL_SCISSOR_TEST);
2459 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2461 /* No filtering for blts */
2462 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2463 GL_NEAREST);
2464 checkGLcall("glTexParameteri");
2465 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2466 GL_NEAREST);
2467 checkGLcall("glTexParameteri");
2468 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2469 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2470 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2471 checkGLcall("glTexEnvi");
2473 /* This is for color keying */
2474 if(Flags & DDBLT_KEYSRC) {
2475 glEnable(GL_ALPHA_TEST);
2476 checkGLcall("glEnable GL_ALPHA_TEST");
2477 glAlphaFunc(GL_NOTEQUAL, 0.0);
2478 checkGLcall("glAlphaFunc\n");
2479 } else {
2480 glDisable(GL_ALPHA_TEST);
2481 checkGLcall("glDisable GL_ALPHA_TEST");
2484 /* Draw a textured quad
2486 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2488 glBegin(GL_QUADS);
2490 glColor3d(1.0f, 1.0f, 1.0f);
2491 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2492 glVertex3f(rect.x1,
2493 rect.y1,
2494 0.0);
2496 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2497 glVertex3f(rect.x1, rect.y2, 0.0);
2499 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2500 glVertex3f(rect.x2,
2501 rect.y2,
2502 0.0);
2504 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2505 glVertex3f(rect.x2,
2506 rect.y1,
2507 0.0);
2508 glEnd();
2509 checkGLcall("glEnd");
2511 /* Unbind the texture */
2512 glBindTexture(GL_TEXTURE_2D, 0);
2513 checkGLcall("glEnable glBindTexture");
2515 /* Restore the old settings */
2516 if(oldLight) {
2517 glEnable(GL_LIGHTING);
2518 checkGLcall("glEnable GL_LIGHTING");
2520 if(oldFog) {
2521 glEnable(GL_FOG);
2522 checkGLcall("glEnable GL_FOG");
2524 if(oldDepth) {
2525 glEnable(GL_DEPTH_TEST);
2526 checkGLcall("glEnable GL_DEPTH_TEST");
2528 if(oldBlend) {
2529 glEnable(GL_BLEND);
2530 checkGLcall("glEnable GL_BLEND");
2532 if(oldCull) {
2533 glEnable(GL_CULL_FACE);
2534 checkGLcall("glEnable GL_CULL_FACE");
2536 if(oldStencil) {
2537 glEnable(GL_STENCIL_TEST);
2538 checkGLcall("glEnable GL_STENCIL_TEST");
2540 if(!oldAlpha) {
2541 glDisable(GL_ALPHA_TEST);
2542 checkGLcall("glDisable GL_ALPHA_TEST");
2543 } else {
2544 glEnable(GL_ALPHA_TEST);
2545 checkGLcall("glEnable GL_ALPHA_TEST");
2547 if (GL_SUPPORT(NV_REGISTER_COMBINERS) && oldNVRegisterCombiners) {
2548 glEnable(GL_REGISTER_COMBINERS_NV);
2549 checkGLcall("glEnable GL_REGISTER_COMBINERS_NV");
2552 glAlphaFunc(alphafunc, alpharef);
2553 checkGLcall("glAlphaFunc\n");
2555 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2556 glDrawBuffer(oldDraw);
2559 /* Restore the color key flags */
2560 if(oldCKey != Src->CKeyFlags) {
2561 Src->CKeyFlags = oldCKey;
2564 /* Restore the old color key */
2565 if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
2566 This->SrcBltCKey = oldBltCKey;
2568 LEAVE_GL();
2570 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2571 This->Flags |= SFLAG_GLDIRTY;
2573 return WINED3D_OK;
2577 /* Blt from rendertarget to texture? */
2578 if( (SrcSurface == swapchain->frontBuffer) ||
2579 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2580 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2581 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2582 UINT row;
2583 WINED3DRECT srect;
2584 float xrel, yrel;
2586 TRACE("Blt from rendertarget to texture\n");
2588 /* Call preload for the surface to make sure it isn't dirty */
2589 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2591 if(SrcRect) {
2592 srect.x1 = SrcRect->left;
2593 srect.y1 = SrcRect->top;
2594 srect.x2 = SrcRect->right;
2595 srect.y2 = SrcRect->bottom;
2596 } else {
2597 srect.x1 = 0;
2598 srect.y1 = 0;
2599 srect.x2 = Src->currentDesc.Width;
2600 srect.y2 = Src->currentDesc.Height;
2603 ENTER_GL();
2605 /* Bind the target texture */
2606 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2607 checkGLcall("glBindTexture");
2608 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2609 glReadBuffer(GL_BACK);
2610 } else {
2611 glReadBuffer(GL_FRONT);
2613 checkGLcall("glReadBuffer");
2615 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2616 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2618 /* I have to process this row by row to swap the image,
2619 * otherwise it would be upside down, so streching in y direction
2620 * doesn't cost extra time
2622 * However, streching in x direction can be avoided if not necessary
2624 for(row = rect.y1; row < rect.y2; row++) {
2625 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2626 /* Well, that stuff works, but it's very slow.
2627 * find a better way instead
2629 UINT col;
2630 for(col = rect.x1; col < rect.x2; col++) {
2631 glCopyTexSubImage2D(GL_TEXTURE_2D,
2632 0, /* level */
2633 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2634 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2635 1, 1);
2637 } else {
2638 glCopyTexSubImage2D(GL_TEXTURE_2D,
2639 0, /* level */
2640 rect.x1, rect.y2 + rect.y1 - row - 1, /* xoffset, yoffset */
2641 srect.x1, row - rect.y1,
2642 rect.x2-rect.x1, 1);
2646 vcheckGLcall("glCopyTexSubImage2D");
2647 LEAVE_GL();
2649 if(!(This->Flags & SFLAG_DONOTFREE)) {
2650 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2651 This->resource.allocatedMemory = NULL;
2652 } else {
2653 This->Flags |= SFLAG_GLDIRTY;
2656 return WINED3D_OK;
2661 if (Flags & DDBLT_COLORFILL) {
2662 /* This is easy to handle for the D3D Device... */
2663 DWORD color;
2664 IWineD3DSwapChainImpl *implSwapChain;
2666 TRACE("Colorfill\n");
2668 /* The color as given in the Blt function is in the format of the frame-buffer...
2669 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2671 if (This->resource.format == WINED3DFMT_P8) {
2672 if (This->palette) {
2673 color = ((0xFF000000) |
2674 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2675 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2676 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2677 } else {
2678 color = 0xFF000000;
2681 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2682 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2683 color = 0xFFFFFFFF;
2684 } else {
2685 color = ((0xFF000000) |
2686 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2687 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2688 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2691 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2692 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2693 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2695 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2696 color = DDBltFx->u5.dwFillColor;
2698 else {
2699 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2700 return WINED3DERR_INVALIDCALL;
2703 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2704 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2705 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2706 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2707 glDrawBuffer(GL_BACK);
2708 checkGLcall("glDrawBuffer(GL_BACK)");
2710 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2711 glDrawBuffer(GL_FRONT);
2712 checkGLcall("glDrawBuffer(GL_FRONT)");
2714 else {
2715 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2716 return WINED3DERR_INVALIDCALL;
2719 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2721 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2722 1 /* Number of rectangles */,
2723 &rect,
2724 WINED3DCLEAR_TARGET,
2725 color,
2726 0.0 /* Z */,
2727 0 /* Stencil */);
2729 /* Restore the original draw buffer */
2730 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2731 glDrawBuffer(GL_BACK);
2732 vcheckGLcall("glDrawBuffer");
2735 return WINED3D_OK;
2738 /* Default: Fall back to the generic blt */
2739 return WINED3DERR_INVALIDCALL;
2742 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2743 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2744 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2745 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2746 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2748 /* Special cases for RenderTargets */
2749 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2750 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2751 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2754 /* For the rest call the X11 surface implementation.
2755 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2756 * other Blts are rather rare
2758 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2761 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2762 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2763 TRACE("(%p)->(%x)\n", This, Flags);
2765 switch (Flags)
2767 case DDGBS_CANBLT:
2768 case DDGBS_ISBLTDONE:
2769 return DD_OK;
2771 default:
2772 return DDERR_INVALIDPARAMS;
2776 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2777 /* XXX: DDERR_INVALIDSURFACETYPE */
2779 TRACE("(%p)->(%08x)\n",iface,Flags);
2780 switch (Flags) {
2781 case DDGFS_CANFLIP:
2782 case DDGFS_ISFLIPDONE:
2783 return DD_OK;
2785 default:
2786 return DDERR_INVALIDPARAMS;
2790 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2791 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2792 TRACE("(%p)\n", This);
2794 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2797 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2798 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2799 TRACE("(%p)\n", This);
2801 /* So far we don't lose anything :) */
2802 This->Flags &= ~SFLAG_LOST;
2803 return WINED3D_OK;
2806 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2807 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2808 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2809 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2811 /* Special cases for RenderTargets */
2812 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2813 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2815 RECT SrcRect, DstRect;
2816 DWORD Flags=0;
2818 if(rsrc) {
2819 SrcRect.left = rsrc->left;
2820 SrcRect.top= rsrc->top;
2821 SrcRect.bottom = rsrc->bottom;
2822 SrcRect.right = rsrc->right;
2823 } else {
2824 SrcRect.left = 0;
2825 SrcRect.top = 0;
2826 SrcRect.right = srcImpl->currentDesc.Width;
2827 SrcRect.bottom = srcImpl->currentDesc.Height;
2830 DstRect.left = dstx;
2831 DstRect.top=dsty;
2832 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2833 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2835 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2836 if(trans & DDBLTFAST_SRCCOLORKEY)
2837 Flags |= DDBLT_KEYSRC;
2838 if(trans & DDBLTFAST_DESTCOLORKEY)
2839 Flags |= DDBLT_KEYDEST;
2840 if(trans & DDBLTFAST_WAIT)
2841 Flags |= DDBLT_WAIT;
2842 if(trans & DDBLTFAST_DONOTWAIT)
2843 Flags |= DDBLT_DONOTWAIT;
2845 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2849 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2852 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2853 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2854 TRACE("(%p)->(%p)\n", This, Pal);
2856 *Pal = (IWineD3DPalette *) This->palette;
2857 return DD_OK;
2860 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2861 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2862 RGBQUAD col[256];
2863 IWineD3DPaletteImpl *pal = This->palette;
2864 unsigned int n;
2865 TRACE("(%p)\n", This);
2867 if(This->resource.format == WINED3DFMT_P8 ||
2868 This->resource.format == WINED3DFMT_A8P8)
2870 TRACE("Dirtifying surface\n");
2871 This->Flags |= SFLAG_DIRTY;
2874 if(This->Flags & SFLAG_DIBSECTION) {
2875 TRACE("(%p): Updating the hdc's palette\n", This);
2876 for (n=0; n<256; n++) {
2877 if(pal) {
2878 col[n].rgbRed = pal->palents[n].peRed;
2879 col[n].rgbGreen = pal->palents[n].peGreen;
2880 col[n].rgbBlue = pal->palents[n].peBlue;
2881 } else {
2882 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2883 /* Use the default device palette */
2884 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2885 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2886 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2888 col[n].rgbReserved = 0;
2890 SetDIBColorTable(This->hDC, 0, 256, col);
2893 return WINED3D_OK;
2896 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2897 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2898 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2899 TRACE("(%p)->(%p)\n", This, Pal);
2901 if(This->palette != NULL)
2902 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2903 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2905 if(PalImpl != NULL) {
2906 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2907 /* Set the device's main palette if the palette
2908 * wasn't a primary palette before
2910 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2911 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2912 unsigned int i;
2914 for(i=0; i < 256; i++) {
2915 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2919 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2922 This->palette = PalImpl;
2924 return IWineD3DSurface_RealizePalette(iface);
2927 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2928 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2929 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
2931 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2932 FIXME(" colorkey value not supported (%08x) !\n", Flags);
2933 return DDERR_INVALIDPARAMS;
2936 /* Dirtify the surface, but only if a key was changed */
2937 if(CKey) {
2938 switch (Flags & ~DDCKEY_COLORSPACE) {
2939 case DDCKEY_DESTBLT:
2940 This->DestBltCKey = *CKey;
2941 This->CKeyFlags |= DDSD_CKDESTBLT;
2942 break;
2944 case DDCKEY_DESTOVERLAY:
2945 This->DestOverlayCKey = *CKey;
2946 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2947 break;
2949 case DDCKEY_SRCOVERLAY:
2950 This->SrcOverlayCKey = *CKey;
2951 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2952 break;
2954 case DDCKEY_SRCBLT:
2955 This->SrcBltCKey = *CKey;
2956 This->CKeyFlags |= DDSD_CKSRCBLT;
2957 break;
2960 else {
2961 switch (Flags & ~DDCKEY_COLORSPACE) {
2962 case DDCKEY_DESTBLT:
2963 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2964 break;
2966 case DDCKEY_DESTOVERLAY:
2967 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2968 break;
2970 case DDCKEY_SRCOVERLAY:
2971 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2972 break;
2974 case DDCKEY_SRCBLT:
2975 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2976 break;
2980 return WINED3D_OK;
2983 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2984 /** Check against the maximum texture sizes supported by the video card **/
2985 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2987 TRACE("%p\n", This);
2988 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2989 /* one of three options
2990 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)
2991 2: Set the texture to the maxium size (bad idea)
2992 3: WARN and return WINED3DERR_NOTAVAILABLE;
2993 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.
2995 WARN("(%p) Creating an oversized surface\n", This);
2996 This->Flags |= SFLAG_OVERSIZE;
2998 /* This will be initialized on the first blt */
2999 This->glRect.left = 0;
3000 This->glRect.top = 0;
3001 This->glRect.right = 0;
3002 This->glRect.bottom = 0;
3003 } else {
3004 /* No oversize, gl rect is the full texture size */
3005 This->Flags &= ~SFLAG_OVERSIZE;
3006 This->glRect.left = 0;
3007 This->glRect.top = 0;
3008 This->glRect.right = This->pow2Width;
3009 This->glRect.bottom = This->pow2Height;
3012 return WINED3D_OK;
3015 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3016 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3017 DWORD ret;
3018 TRACE("(%p)\n", This);
3020 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3021 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3022 ie pitch = (width/4) * bytes per block */
3023 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3024 ret = (This->currentDesc.Width >> 2) << 3;
3025 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3026 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3027 ret = (This->currentDesc.Width >> 2) << 4;
3028 else {
3029 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3030 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3031 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3032 } else {
3033 ret = This->bytesPerPixel * This->pow2Width;
3035 /* Surfaces are 32 bit aligned */
3036 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3038 TRACE("(%p) Returning %d\n", This, ret);
3039 return ret;
3042 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3043 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3045 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3047 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3049 TRACE("(%p): Not an overlay surface\n", This);
3050 return DDERR_NOTAOVERLAYSURFACE;
3053 return WINED3D_OK;
3056 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3057 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3059 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3061 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3063 TRACE("(%p): Not an overlay surface\n", This);
3064 return DDERR_NOTAOVERLAYSURFACE;
3067 return WINED3D_OK;
3070 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3071 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3072 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3074 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3076 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3078 TRACE("(%p): Not an overlay surface\n", This);
3079 return DDERR_NOTAOVERLAYSURFACE;
3082 return WINED3D_OK;
3085 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3086 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3087 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3088 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3090 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3092 TRACE("(%p): Not an overlay surface\n", This);
3093 return DDERR_NOTAOVERLAYSURFACE;
3096 return WINED3D_OK;
3099 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3101 /* IUnknown */
3102 IWineD3DSurfaceImpl_QueryInterface,
3103 IWineD3DSurfaceImpl_AddRef,
3104 IWineD3DSurfaceImpl_Release,
3105 /* IWineD3DResource */
3106 IWineD3DSurfaceImpl_GetParent,
3107 IWineD3DSurfaceImpl_GetDevice,
3108 IWineD3DSurfaceImpl_SetPrivateData,
3109 IWineD3DSurfaceImpl_GetPrivateData,
3110 IWineD3DSurfaceImpl_FreePrivateData,
3111 IWineD3DSurfaceImpl_SetPriority,
3112 IWineD3DSurfaceImpl_GetPriority,
3113 IWineD3DSurfaceImpl_PreLoad,
3114 IWineD3DSurfaceImpl_GetType,
3115 /* IWineD3DSurface */
3116 IWineD3DSurfaceImpl_GetContainerParent,
3117 IWineD3DSurfaceImpl_GetContainer,
3118 IWineD3DSurfaceImpl_GetDesc,
3119 IWineD3DSurfaceImpl_LockRect,
3120 IWineD3DSurfaceImpl_UnlockRect,
3121 IWineD3DSurfaceImpl_GetDC,
3122 IWineD3DSurfaceImpl_ReleaseDC,
3123 IWineD3DSurfaceImpl_Flip,
3124 IWineD3DSurfaceImpl_Blt,
3125 IWineD3DSurfaceImpl_GetBltStatus,
3126 IWineD3DSurfaceImpl_GetFlipStatus,
3127 IWineD3DSurfaceImpl_IsLost,
3128 IWineD3DSurfaceImpl_Restore,
3129 IWineD3DSurfaceImpl_BltFast,
3130 IWineD3DSurfaceImpl_GetPalette,
3131 IWineD3DSurfaceImpl_SetPalette,
3132 IWineD3DSurfaceImpl_RealizePalette,
3133 IWineD3DSurfaceImpl_SetColorKey,
3134 IWineD3DSurfaceImpl_GetPitch,
3135 IWineD3DSurfaceImpl_SetMem,
3136 IWineD3DSurfaceImpl_SetOverlayPosition,
3137 IWineD3DSurfaceImpl_GetOverlayPosition,
3138 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3139 IWineD3DSurfaceImpl_UpdateOverlay,
3140 /* Internal use: */
3141 IWineD3DSurfaceImpl_CleanDirtyRect,
3142 IWineD3DSurfaceImpl_AddDirtyRect,
3143 IWineD3DSurfaceImpl_LoadTexture,
3144 IWineD3DSurfaceImpl_SaveSnapshot,
3145 IWineD3DSurfaceImpl_SetContainer,
3146 IWineD3DSurfaceImpl_SetPBufferState,
3147 IWineD3DSurfaceImpl_SetGlTextureDesc,
3148 IWineD3DSurfaceImpl_GetGlDesc,
3149 IWineD3DSurfaceImpl_GetData,
3150 IWineD3DSurfaceImpl_SetFormat,
3151 IWineD3DSurfaceImpl_PrivateSetup