wined3d: Do not perform a NULL check on riid (Coverity).
[wine/multimedia.git] / dlls / wined3d / surface.c
blobde263b9e6eba9bedc39667422f37b0a41d59d52a
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 width, 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);
192 if (IsEqualGUID(riid, &IID_IUnknown)
193 || IsEqualGUID(riid, &IID_IWineD3DBase)
194 || IsEqualGUID(riid, &IID_IWineD3DResource)
195 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
196 IUnknown_AddRef((IUnknown*)iface);
197 *ppobj = This;
198 return S_OK;
200 *ppobj = NULL;
201 return E_NOINTERFACE;
204 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
205 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
206 ULONG ref = InterlockedIncrement(&This->resource.ref);
207 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
208 return ref;
211 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
212 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
213 ULONG ref = InterlockedDecrement(&This->resource.ref);
214 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
215 if (ref == 0) {
216 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
217 TRACE("(%p) : cleaning up\n", This);
218 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
219 ENTER_GL();
220 TRACE("Deleting texture %d\n", This->glDescription.textureName);
221 glDeleteTextures(1, &This->glDescription.textureName);
222 LEAVE_GL();
225 if(This->Flags & SFLAG_DIBSECTION) {
226 /* Release the DC */
227 SelectObject(This->hDC, This->dib.holdbitmap);
228 DeleteDC(This->hDC);
229 /* Release the DIB section */
230 DeleteObject(This->dib.DIBsection);
231 This->dib.bitmap_data = NULL;
232 This->resource.allocatedMemory = NULL;
234 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
236 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
237 if(iface == device->ddraw_primary)
238 device->ddraw_primary = NULL;
240 TRACE("(%p) Released\n", This);
241 HeapFree(GetProcessHeap(), 0, This);
244 return ref;
247 /* ****************************************************
248 IWineD3DSurface IWineD3DResource parts follow
249 **************************************************** */
250 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
251 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
254 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
255 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
258 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
259 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
262 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
263 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
266 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
267 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
270 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
271 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
274 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
275 /* TODO: re-write the way textures and managed,
276 * use a 'opengl context manager' to manage RenderTarget surfaces
277 ** *********************************************************/
279 /* TODO: check for locks */
280 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
281 IWineD3DBaseTexture *baseTexture = NULL;
282 TRACE("(%p)Checking to see if the container is a base texture\n", This);
283 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
284 TRACE("Passing to conatiner\n");
285 IWineD3DBaseTexture_PreLoad(baseTexture);
286 IWineD3DBaseTexture_Release(baseTexture);
287 } else {
288 TRACE("(%p) : About to load surface\n", This);
289 ENTER_GL();
290 #if 0 /* TODO: context manager support */
291 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
292 #endif
293 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
294 if (!This->glDescription.level) {
295 if (!This->glDescription.textureName) {
296 glGenTextures(1, &This->glDescription.textureName);
297 checkGLcall("glGenTextures");
298 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
300 glBindTexture(This->glDescription.target, This->glDescription.textureName);
301 checkGLcall("glBindTexture");
302 IWineD3DSurface_LoadTexture(iface);
303 /* This is where we should be reducing the amount of GLMemoryUsed */
304 } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
305 /* assume this is a coding error not a real error for now */
306 FIXME("Mipmap surface has a glTexture bound to it!\n");
308 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
309 /* Tell opengl to try and keep this texture in video ram (well mostly) */
310 GLclampf tmp;
311 tmp = 0.9f;
312 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
314 /* TODO: disable texture support, if it wastn't enabled when we entered. */
315 #if 0 /* TODO: context manager support */
316 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
317 /* we don't care when the state is disabled(if atall) */);
318 #endif
319 LEAVE_GL();
321 return;
324 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
325 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
326 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
329 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
330 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
331 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
334 /* ******************************************************
335 IWineD3DSurface IWineD3DSurface parts follow
336 ****************************************************** */
338 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
339 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
340 IWineD3DBase *container = 0;
342 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
344 if (!ppContainer) {
345 ERR("Called without a valid ppContainer.\n");
348 /** From MSDN:
349 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
350 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
351 * GetContainer will return the Direct3D device used to create the surface.
353 if (This->container) {
354 container = This->container;
355 } else {
356 container = (IWineD3DBase *)This->resource.wineD3DDevice;
359 TRACE("Relaying to QueryInterface\n");
360 return IUnknown_QueryInterface(container, riid, ppContainer);
363 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
364 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
366 TRACE("(%p) : copying into %p\n", This, pDesc);
367 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
368 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
369 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
370 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
371 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
372 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
373 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
374 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
375 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
376 return WINED3D_OK;
379 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
380 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
381 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
382 if (This->glDescription.textureName == 0 && textureName != 0) {
383 This->Flags |= SFLAG_DIRTY;
384 IWineD3DSurface_AddDirtyRect(iface, NULL);
386 This->glDescription.textureName = textureName;
387 This->glDescription.target = target;
390 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
391 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
392 TRACE("(%p) : returning %p\n", This, &This->glDescription);
393 *glDescription = &This->glDescription;
396 /* TODO: think about moving this down to resource? */
397 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
398 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
399 /* 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 */
400 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
401 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
403 return (CONST void*)(This->resource.allocatedMemory);
406 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
407 long j;
408 void *mem;
409 GLint fmt;
410 GLint type;
412 switch(This->resource.format)
414 case WINED3DFMT_P8:
416 /* GL can't return palettized data, so read ARGB pixels into a
417 * separate block of memory and convert them into palettized format
418 * in software. Slow, but if the app means to use palettized render
419 * targets and locks it...
421 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
422 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
423 * for the color channels when palettizing the colors.
425 fmt = GL_RGB;
426 type = GL_UNSIGNED_BYTE;
427 pitch *= 3;
428 mem = HeapAlloc(GetProcessHeap(), 0, (rect->bottom - rect->top) * pitch);
429 if(!mem) {
430 ERR("Out of memory\n");
431 return;
434 break;
436 default:
437 mem = dest;
438 fmt = This->glDescription.glFormat;
439 type = This->glDescription.glType;
442 if (rect->left == 0 &&
443 rect->right == This->currentDesc.Width ) {
444 BYTE *row, *top, *bottom;
445 int i;
447 glReadPixels(0, rect->top,
448 This->currentDesc.Width,
449 rect->bottom - rect->top,
450 fmt,
451 type,
452 mem);
454 /* glReadPixels returns the image upside down, and there is no way to prevent this.
455 Flip the lines in software */
456 row = HeapAlloc(GetProcessHeap(), 0, pitch);
457 if(!row) {
458 ERR("Out of memory\n");
459 return;
461 top = mem;
462 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
463 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
464 memcpy(row, top, pitch);
465 memcpy(top, bottom, pitch);
466 memcpy(bottom, row, pitch);
467 top += pitch;
468 bottom -= pitch;
470 HeapFree(GetProcessHeap(), 0, row);
472 if(This->lockedRect.top == 0 && This->lockedRect.bottom == This->currentDesc.Height) {
473 This->Flags &= ~SFLAG_GLDIRTY;
475 } else {
476 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
477 glReadPixels(rect->left,
478 rect->bottom - j - 1,
479 rect->right - rect->left,
481 fmt,
482 type,
483 (char *)mem + (pitch * (j-rect->top)));
487 vcheckGLcall("glReadPixels");
489 if(This->resource.format == WINED3DFMT_P8) {
490 PALETTEENTRY *pal;
491 DWORD width = pitch / 3;
492 int x, y, c;
493 if(This->palette) {
494 pal = This->palette->palents;
495 } else {
496 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
499 for(y = rect->top; y < rect->bottom; y++) {
500 for(x = rect->left; x < rect->right; x++) {
501 /* start lines pixels */
502 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
503 BYTE *green = blue + 1;
504 BYTE *red = green + 1;
506 for(c = 0; c < 256; c++) {
507 if(*red == pal[c].peRed &&
508 *green == pal[c].peGreen &&
509 *blue == pal[c].peBlue)
511 *((BYTE *) dest + y * width + x) = c;
512 break;
517 HeapFree(GetProcessHeap(), 0, mem);
521 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
522 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
523 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
524 IWineD3DSwapChainImpl *swapchain = NULL;
525 static UINT messages = 0; /* holds flags to disable fixme messages */
526 BOOL backbuf = FALSE;
528 /* fixme: should we really lock as such? */
529 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
530 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
531 FIXME("Warning: Surface is in texture memory or pbuffer\n");
532 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
535 if (!(This->Flags & SFLAG_LOCKABLE)) {
536 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
537 texture regions, and since the destination is an unlockable region we need
538 to tolerate this */
539 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
540 /*return WINED3DERR_INVALIDCALL; */
543 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
544 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
546 if (swapchain != NULL || iface == myDevice->render_targets[0] || iface == myDevice->depthStencilBuffer) {
547 if(swapchain != NULL) {
548 int i;
549 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
550 if(iface == swapchain->backBuffer[i]) {
551 backbuf = TRUE;
552 break;
556 if (backbuf) {
557 TRACE("(%p, backBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
558 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
559 TRACE("(%p, frontBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
560 } else if (iface == myDevice->render_targets[0]) {
561 TRACE("(%p, renderTarget) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
562 } else if (iface == myDevice->depthStencilBuffer) {
563 TRACE("(%p, stencilBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
566 if (NULL != swapchain) {
567 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
569 swapchain = NULL;
571 } else {
572 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
575 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
577 if (NULL == pRect) {
578 pLockedRect->pBits = This->resource.allocatedMemory;
579 This->lockedRect.left = 0;
580 This->lockedRect.top = 0;
581 This->lockedRect.right = This->currentDesc.Width;
582 This->lockedRect.bottom = This->currentDesc.Height;
583 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);
584 } else {
585 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
587 if ((pRect->top < 0) ||
588 (pRect->left < 0) ||
589 (pRect->left >= pRect->right) ||
590 (pRect->top >= pRect->bottom) ||
591 (pRect->right > This->currentDesc.Width) ||
592 (pRect->bottom > This->currentDesc.Height))
594 WARN(" Invalid values in pRect !!!\n");
595 return D3DERR_INVALIDCALL;
598 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
599 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
600 } else {
601 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
603 This->lockedRect.left = pRect->left;
604 This->lockedRect.top = pRect->top;
605 This->lockedRect.right = pRect->right;
606 This->lockedRect.bottom = pRect->bottom;
609 if (This->Flags & SFLAG_NONPOW2) {
610 TRACE("Locking non-power 2 texture\n");
613 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
614 /* classic surface TODO: non 2d surfaces?
615 These resources may be POOL_SYSTEMMEM, so they must not access the device */
616 TRACE("locking an ordinarary surface\n");
617 /* Check to see if memory has already been allocated from the surface*/
618 if ((NULL == This->resource.allocatedMemory) ||
619 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
620 /* Non-system memory surfaces */
622 This->Flags &= ~SFLAG_GLDIRTY;
624 /*Surface has no memory currently allocated to it!*/
625 TRACE("(%p) Locking rect\n" , This);
626 if(!This->resource.allocatedMemory) {
627 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
629 if (0 != This->glDescription.textureName) {
630 /* Now I have to copy thing bits back */
631 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
632 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
634 /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
635 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
636 ENTER_GL();
637 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
638 checkGLcall("glActiveTextureARB");
639 LEAVE_GL();
641 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
642 IWineD3DSurface_PreLoad(iface);
644 surface_download_data(This);
646 } else { /* Nothing to do */
647 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
650 if (NULL == pRect) {
651 pLockedRect->pBits = This->resource.allocatedMemory;
652 } else{
653 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
654 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
655 } else {
656 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
660 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
661 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
662 GLint prev_store;
663 GLint prev_read;
664 BOOL notInContext = FALSE;
665 IWineD3DSwapChainImpl *targetSwapChain = NULL;
668 ENTER_GL();
671 * for render->surface copy begin to begin of allocatedMemory
672 * unlock can be more easy
675 TRACE("locking a render target\n");
677 if (This->resource.allocatedMemory == NULL)
678 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
680 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
681 pLockedRect->pBits = This->resource.allocatedMemory;
683 glFlush();
684 vcheckGLcall("glFlush");
685 glGetIntegerv(GL_READ_BUFFER, &prev_read);
686 vcheckGLcall("glIntegerv");
687 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
688 vcheckGLcall("glIntegerv");
690 /* Here's what we have to do:
691 See if the swapchain has the same context as the renderTarget or the surface is the render target.
692 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
693 and use the front back buffer as required.
694 if not, we need to switch contexts and then switchback at the end.
696 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
697 IWineD3DSurface_GetContainer(myDevice->render_targets[0], &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
699 /* 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! */
700 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->render_targets[0]) {
701 if (swapchain && iface == swapchain->frontBuffer) {
702 TRACE("locking front\n");
703 glReadBuffer(GL_FRONT);
705 else if (iface == myDevice->render_targets[0] || backbuf) {
706 TRACE("locking back buffer\n");
707 glReadBuffer(GL_BACK);
708 } else if (iface == myDevice->depthStencilBuffer) {
709 FIXME("Stencil Buffer lock unsupported for now\n");
710 } else {
711 FIXME("(%p) Shouldn't have got here!\n", This);
712 glReadBuffer(GL_BACK);
714 } else if (swapchain != NULL) {
715 IWineD3DSwapChainImpl *implSwapChain;
716 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
717 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
718 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
719 if (backbuf) {
720 glReadBuffer(GL_BACK);
721 } else if (iface == swapchain->frontBuffer) {
722 glReadBuffer(GL_FRONT);
723 } else if (iface == myDevice->depthStencilBuffer) {
724 FIXME("Stencil Buffer lock unsupported for now\n");
725 } else {
726 FIXME("Should have got here!\n");
727 glReadBuffer(GL_BACK);
729 } else {
730 /* We need to switch contexts to be able to read the buffer!!! */
731 FIXME("The buffer requested isn't in the current openGL context\n");
732 notInContext = TRUE;
733 /* TODO: check the contexts, to see if were shared with the current context */
735 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
737 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
738 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
740 /** the depth stencil in openGL has a format of GL_FLOAT
741 * which should be good for WINED3DFMT_D16_LOCKABLE
742 * and WINED3DFMT_D16
743 * it is unclear what format the stencil buffer is in except.
744 * 'Each index is converted to fixed point...
745 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
746 * mappings in the table GL_PIXEL_MAP_S_TO_S.
747 * glReadPixels(This->lockedRect.left,
748 * This->lockedRect.bottom - j - 1,
749 * This->lockedRect.right - This->lockedRect.left,
750 * 1,
751 * GL_DEPTH_COMPONENT,
752 * type,
753 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
754 *****************************************/
755 if (!notInContext) { /* Only read the buffer if it's in the current context */
756 switch(wined3d_settings.rendertargetlock_mode) {
757 case RTL_AUTO:
758 case RTL_READDRAW:
759 case RTL_READTEX:
760 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
761 break;
763 case RTL_TEXDRAW:
764 case RTL_TEXTEX:
765 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
766 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
767 break;
769 case RTL_DISABLE:
771 static BOOL warned = FALSE;
772 if(!warned) {
773 ERR("Application tries to lock the render target, but render target locking is disabled\n");
774 warned = TRUE;
777 break;
780 TRACE("Resetting buffer\n");
782 glReadBuffer(prev_read);
783 vcheckGLcall("glReadBuffer");
785 LEAVE_GL();
787 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
789 if (!messages & 1) {
790 FIXME("TODO stencil depth surface locking surf%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
793 glReadPixels(This->lockedRect.left,
794 This->lockedRect.bottom - j - 1,
795 This->lockedRect.right - This->lockedRect.left,
797 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
801 messages |= 1;
803 } else {
804 FIXME("unsupported locking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
807 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
808 /* Don't dirtify */
809 } else {
810 IWineD3DBaseTexture *pBaseTexture;
812 * Dirtify on lock
813 * as seen in msdn docs
815 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
817 /** Dirtify Container if needed */
818 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
819 TRACE("Making container dirty\n");
820 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
821 IWineD3DBaseTexture_Release(pBaseTexture);
822 } else {
823 TRACE("Surface is standalone, no need to dirty the container\n");
827 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
829 This->Flags |= SFLAG_LOCKED;
830 return WINED3D_OK;
833 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
834 GLint prev_store;
835 GLint prev_rasterpos[4];
836 GLint skipBytes = 0;
837 BOOL storechanged = FALSE;
838 GLint fmt, type;
839 void *mem;
841 glDisable(GL_TEXTURE_2D);
842 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
843 glDisable(GL_TEXTURE_1D);
844 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
846 glFlush();
847 vcheckGLcall("glFlush");
848 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
849 vcheckGLcall("glIntegerv");
850 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
851 vcheckGLcall("glIntegerv");
852 glPixelZoom(1.0, -1.0);
853 vcheckGLcall("glPixelZoom");
855 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
856 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
857 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
859 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
860 vcheckGLcall("glRasterPos2f");
862 /* Some drivers(radeon dri, others?) don't like exceptions during
863 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
864 * after ReleaseDC. Reading it will cause an exception, which x11drv will
865 * catch to put the dib section in InSync mode, which leads to a crash
866 * and a blocked x server on my radeon card.
868 * The following lines read the dib section so it is put in inSync mode
869 * before glDrawPixels is called and the crash is prevented. There won't
870 * be any interfering gdi accesses, because UnlockRect is called from
871 * ReleaseDC, and the app won't use the dc any more afterwards.
873 if(This->Flags & SFLAG_DIBSECTION) {
874 volatile BYTE read;
875 read = This->resource.allocatedMemory[0];
878 switch (This->resource.format) {
879 /* No special care needed */
880 case WINED3DFMT_A4R4G4B4:
881 case WINED3DFMT_R5G6B5:
882 case WINED3DFMT_A1R5G5B5:
883 case WINED3DFMT_R8G8B8:
884 type = This->glDescription.glType;
885 fmt = This->glDescription.glFormat;
886 mem = This->resource.allocatedMemory;
887 break;
889 case WINED3DFMT_X4R4G4B4:
891 int size;
892 unsigned short *data;
893 data = (unsigned short *)This->resource.allocatedMemory;
894 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
895 while(size > 0) {
896 *data |= 0xF000;
897 data++;
898 size--;
900 type = This->glDescription.glType;
901 fmt = This->glDescription.glFormat;
902 mem = This->resource.allocatedMemory;
904 break;
906 case WINED3DFMT_X1R5G5B5:
908 int size;
909 unsigned short *data;
910 data = (unsigned short *)This->resource.allocatedMemory;
911 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
912 while(size > 0) {
913 *data |= 0x8000;
914 data++;
915 size--;
917 type = This->glDescription.glType;
918 fmt = This->glDescription.glFormat;
919 mem = This->resource.allocatedMemory;
921 break;
923 case WINED3DFMT_X8R8G8B8:
925 /* make sure the X byte is set to alpha on, since it
926 could be any random value. This fixes the intro movie in Pirates! */
927 int size;
928 unsigned int *data;
929 data = (unsigned int *)This->resource.allocatedMemory;
930 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
931 while(size > 0) {
932 *data |= 0xFF000000;
933 data++;
934 size--;
937 /* Fall through */
939 case WINED3DFMT_A8R8G8B8:
941 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
942 vcheckGLcall("glPixelStorei");
943 storechanged = TRUE;
944 type = This->glDescription.glType;
945 fmt = This->glDescription.glFormat;
946 mem = This->resource.allocatedMemory;
948 break;
950 case WINED3DFMT_A2R10G10B10:
952 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
953 vcheckGLcall("glPixelStorei");
954 storechanged = TRUE;
955 type = This->glDescription.glType;
956 fmt = This->glDescription.glFormat;
957 mem = This->resource.allocatedMemory;
959 break;
961 case WINED3DFMT_P8:
963 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
964 int height = This->glRect.bottom - This->glRect.top;
965 type = GL_UNSIGNED_BYTE;
966 fmt = GL_RGBA;
968 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
969 if(!mem) {
970 ERR("Out of memory\n");
971 return;
973 d3dfmt_convert_surface(This->resource.allocatedMemory,
974 mem,
975 pitch,
976 pitch,
977 height,
978 pitch * 4,
979 CONVERT_PALETTED,
980 This);
982 break;
984 default:
985 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
987 /* Give it a try */
988 type = This->glDescription.glType;
989 fmt = This->glDescription.glFormat;
990 mem = This->resource.allocatedMemory;
993 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
994 (This->lockedRect.bottom - This->lockedRect.top)-1,
995 fmt, type,
996 mem);
997 checkGLcall("glDrawPixels");
998 glPixelZoom(1.0,1.0);
999 vcheckGLcall("glPixelZoom");
1001 glRasterPos3iv(&prev_rasterpos[0]);
1002 vcheckGLcall("glRasterPos3iv");
1004 /* Reset to previous pack row length */
1005 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1006 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1007 if(storechanged) {
1008 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
1009 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1012 if(mem != This->resource.allocatedMemory) HeapFree(GetProcessHeap(), 0, mem);
1013 return;
1016 static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
1017 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1018 float glTexCoord[4];
1020 glTexCoord[0] = 0.0; /* left */
1021 glTexCoord[1] = (float) This->currentDesc.Width / (float) This->pow2Width; /* right */
1022 glTexCoord[2] = 0.0; /* top */
1023 glTexCoord[3] = (float) This->currentDesc.Height / (float) This->pow2Height; /* bottom */
1025 IWineD3DSurface_PreLoad(iface);
1027 ENTER_GL();
1029 /* Disable some fancy graphics effects */
1030 glDisable(GL_LIGHTING);
1031 checkGLcall("glDisable GL_LIGHTING");
1032 glDisable(GL_DEPTH_TEST);
1033 checkGLcall("glDisable GL_DEPTH_TEST");
1034 glDisable(GL_FOG);
1035 checkGLcall("glDisable GL_FOG");
1036 glDisable(GL_CULL_FACE);
1037 checkGLcall("glDisable GL_CULL_FACE");
1038 glDisable(GL_BLEND);
1039 checkGLcall("glDisable GL_BLEND");
1040 glDisable(GL_STENCIL_TEST);
1041 checkGLcall("glDisable GL_STENCIL_TEST");
1043 glEnable(GL_TEXTURE_2D);
1044 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1045 checkGLcall("glEnable glBindTexture");
1047 /* No filtering for blts */
1048 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1049 checkGLcall("glTexParameteri");
1050 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1051 checkGLcall("glTexParameteri");
1053 /* Start drawing a quad */
1054 glBegin(GL_QUADS);
1056 glColor3d(1.0f, 1.0f, 1.0f);
1057 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1058 glVertex3f(0, 0, 0.0);
1060 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1061 glVertex3f(0, This->currentDesc.Height, 0.0);
1063 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1064 glVertex3d(This->currentDesc.Width, This->currentDesc.Height, 0.0);
1066 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1067 glVertex3f(This->currentDesc.Width, 0, 0.0);
1069 glEnd();
1070 checkGLcall("glEnd");
1072 /* Unbind the texture */
1073 glBindTexture(GL_TEXTURE_2D, 0);
1074 checkGLcall("glEnable glBindTexture");
1076 LEAVE_GL();
1079 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1080 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1081 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1082 const char *buffername = "";
1083 IWineD3DSwapChainImpl *swapchain = NULL;
1084 BOOL backbuf = FALSE;
1086 if (!(This->Flags & SFLAG_LOCKED)) {
1087 WARN("trying to Unlock an unlocked surf@%p\n", This);
1088 return WINED3DERR_INVALIDCALL;
1091 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
1092 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1094 if(swapchain) {
1095 int i;
1096 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
1097 if(iface == swapchain->backBuffer[i]) {
1098 backbuf = TRUE;
1099 break;
1104 if (backbuf) {
1105 buffername = "backBuffer";
1106 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
1107 buffername = "frontBuffer";
1108 } else if (iface == myDevice->depthStencilBuffer) {
1109 buffername = "depthStencilBuffer";
1110 } else if (iface == myDevice->render_targets[0]) {
1111 buffername = "renderTarget";
1115 if (swapchain != NULL) {
1116 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1119 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
1121 if (!(This->Flags & SFLAG_DIRTY)) {
1122 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1123 goto unlock_end;
1126 if (0 == This->resource.usage) { /* classic surface */
1127 IWineD3DBaseTextureImpl *impl;
1128 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1129 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1130 * states need resetting
1132 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1133 if(impl->baseTexture.bindCount) {
1134 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1136 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1138 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
1140 /****************************
1141 * TODO: Render targets are 'special' and
1142 * ?some? locking needs to be passed onto the context manager
1143 * so that it becomes possible to use auxiliary buffers, pbuffers
1144 * render-to-texture, shared, cached contexts etc...
1145 * ****************************/
1146 IWineD3DSwapChainImpl *implSwapChain;
1147 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
1149 if ((backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->render_targets[0]) && wined3d_settings.rendertargetlock_mode != RTL_DISABLE) {
1150 int tex;
1152 ENTER_GL();
1154 /* glDrawPixels transforms the raster position as though it was a vertex -
1155 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1156 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1157 myDevice->last_was_rhw = TRUE;
1158 /* Apply the projection and world matrices, it sets up orthogonal projection due to last_was_rhw */
1159 StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock);
1160 StateTable[STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))].apply(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), myDevice->stateBlock);
1161 /* Will reapply the projection matrix too */
1162 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL);
1164 if (iface == implSwapChain->frontBuffer) {
1165 glDrawBuffer(GL_FRONT);
1166 checkGLcall("glDrawBuffer GL_FRONT");
1167 } else if (backbuf || iface == myDevice->render_targets[0]) {
1168 glDrawBuffer(GL_BACK);
1169 checkGLcall("glDrawBuffer GL_BACK");
1172 /* Disable higher textures before calling glDrawPixels */
1173 for(tex = 1; tex < GL_LIMITS(samplers); tex++) {
1174 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1175 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + tex));
1176 checkGLcall("glActiveTextureARB");
1178 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(tex));
1179 glDisable(GL_TEXTURE_2D);
1180 checkGLcall("glDisable GL_TEXTURE_2D");
1181 glDisable(GL_TEXTURE_1D);
1182 checkGLcall("glDisable GL_TEXTURE_1D");
1184 /* Activate texture 0, but don't disable it necessarily */
1185 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1186 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1187 checkGLcall("glActiveTextureARB");
1189 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
1191 /* And back buffers are not blended. Disable the depth test,
1192 that helps performance */
1193 glDisable(GL_BLEND);
1194 glDisable(GL_DEPTH_TEST);
1195 glDisable(GL_FOG);
1197 switch(wined3d_settings.rendertargetlock_mode) {
1198 case RTL_AUTO:
1199 case RTL_READDRAW:
1200 case RTL_TEXDRAW:
1201 flush_to_framebuffer_drawpixels(This);
1202 break;
1204 case RTL_READTEX:
1205 case RTL_TEXTEX:
1206 flush_to_framebuffer_texture(iface);
1207 break;
1209 case RTL_DISABLE:
1211 static BOOL warned = FALSE;
1212 if(!warned) {
1213 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1214 warned = TRUE;
1217 break;
1220 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1221 glDrawBuffer(GL_BACK);
1222 vcheckGLcall("glDrawBuffer");
1224 if(myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_TRUE ||
1225 myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_USEW) glEnable(GL_DEPTH_TEST);
1226 if (myDevice->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1227 if (myDevice->stateBlock->renderState[WINED3DRS_FOGENABLE]) glEnable(GL_FOG);
1229 LEAVE_GL();
1231 /** restore clean dirty state */
1232 IWineD3DSurface_CleanDirtyRect(iface);
1234 } else if(wined3d_settings.rendertargetlock_mode != RTL_DISABLE) {
1235 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1237 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1239 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1241 if (iface == myDevice->depthStencilBuffer) {
1242 FIXME("TODO stencil depth surface unlocking surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1243 } else {
1244 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1247 } else {
1248 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1251 unlock_end:
1252 This->Flags &= ~SFLAG_LOCKED;
1253 memset(&This->lockedRect, 0, sizeof(RECT));
1254 return WINED3D_OK;
1257 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1258 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1259 WINED3DLOCKED_RECT lock;
1260 UINT usage;
1261 BITMAPINFO* b_info;
1262 HDC ddc;
1263 DWORD *masks;
1264 HRESULT hr;
1265 RGBQUAD col[256];
1266 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1268 TRACE("(%p)->(%p)\n",This,pHDC);
1270 if(This->Flags & SFLAG_USERPTR) {
1271 ERR("Not supported on surfaces with an application-provided surfaces\n");
1272 return DDERR_NODC;
1275 /* Give more detailed info for ddraw */
1276 if (This->Flags & SFLAG_DCINUSE)
1277 return DDERR_DCALREADYCREATED;
1279 /* Can't GetDC if the surface is locked */
1280 if (This->Flags & SFLAG_LOCKED)
1281 return WINED3DERR_INVALIDCALL;
1283 memset(&lock, 0, sizeof(lock)); /* To be sure */
1285 /* Create a DIB section if there isn't a hdc yet */
1286 if(!This->hDC) {
1287 int extraline = 0;
1288 SYSTEM_INFO sysInfo;
1290 if(This->Flags & SFLAG_ACTIVELOCK) {
1291 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1294 switch (This->bytesPerPixel) {
1295 case 2:
1296 case 4:
1297 /* Allocate extra space to store the RGB bit masks. */
1298 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1299 break;
1301 case 3:
1302 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1303 break;
1305 default:
1306 /* Allocate extra space for a palette. */
1307 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1308 sizeof(BITMAPINFOHEADER)
1309 + sizeof(RGBQUAD)
1310 * (1 << (This->bytesPerPixel * 8)));
1311 break;
1314 if (!b_info)
1315 return E_OUTOFMEMORY;
1317 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1318 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1319 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1320 * add an extra line to the dib section
1322 GetSystemInfo(&sysInfo);
1323 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1324 extraline = 1;
1325 TRACE("Adding an extra line to the dib section\n");
1328 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1329 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1330 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1331 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1332 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1333 /* Use the full pow2 image size(assigned below) because LockRect
1334 * will need it for a full glGetTexImage call
1336 } else {
1337 b_info->bmiHeader.biWidth = This->pow2Width;
1338 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1339 b_info->bmiHeader.biSizeImage = This->resource.size + extraline * IWineD3DSurface_GetPitch(iface);
1341 b_info->bmiHeader.biPlanes = 1;
1342 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1344 b_info->bmiHeader.biXPelsPerMeter = 0;
1345 b_info->bmiHeader.biYPelsPerMeter = 0;
1346 b_info->bmiHeader.biClrUsed = 0;
1347 b_info->bmiHeader.biClrImportant = 0;
1349 /* Get the bit masks */
1350 masks = (DWORD *) &(b_info->bmiColors);
1351 switch (This->resource.format) {
1352 case WINED3DFMT_R8G8B8:
1353 usage = DIB_RGB_COLORS;
1354 b_info->bmiHeader.biCompression = BI_RGB;
1355 break;
1357 case WINED3DFMT_X1R5G5B5:
1358 case WINED3DFMT_A1R5G5B5:
1359 case WINED3DFMT_A4R4G4B4:
1360 case WINED3DFMT_X4R4G4B4:
1361 case WINED3DFMT_R3G3B2:
1362 case WINED3DFMT_A8R3G3B2:
1363 case WINED3DFMT_A2B10G10R10:
1364 case WINED3DFMT_A8B8G8R8:
1365 case WINED3DFMT_X8B8G8R8:
1366 case WINED3DFMT_A2R10G10B10:
1367 case WINED3DFMT_R5G6B5:
1368 case WINED3DFMT_A16B16G16R16:
1369 usage = 0;
1370 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1371 masks[0] = formatEntry->redMask;
1372 masks[1] = formatEntry->greenMask;
1373 masks[2] = formatEntry->blueMask;
1374 break;
1376 default:
1377 /* Don't know palette */
1378 b_info->bmiHeader.biCompression = BI_RGB;
1379 usage = 0;
1380 break;
1383 ddc = GetDC(0);
1384 if (ddc == 0) {
1385 HeapFree(GetProcessHeap(), 0, b_info);
1386 return HRESULT_FROM_WIN32(GetLastError());
1389 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);
1390 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1391 ReleaseDC(0, ddc);
1393 if (!This->dib.DIBsection) {
1394 ERR("CreateDIBSection failed!\n");
1395 HeapFree(GetProcessHeap(), 0, b_info);
1396 return HRESULT_FROM_WIN32(GetLastError());
1399 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1401 /* copy the existing surface to the dib section */
1402 if(This->resource.allocatedMemory) {
1403 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1404 /* We won't need that any more */
1405 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1406 } else {
1407 /* This is to make LockRect read the gl Texture although memory is allocated */
1408 This->Flags |= SFLAG_GLDIRTY;
1411 HeapFree(GetProcessHeap(), 0, b_info);
1413 /* Use the dib section from now on */
1414 This->resource.allocatedMemory = This->dib.bitmap_data;
1416 /* Now allocate a HDC */
1417 This->hDC = CreateCompatibleDC(0);
1418 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1419 TRACE("using wined3d palette %p\n", This->palette);
1420 SelectPalette(This->hDC,
1421 This->palette ? This->palette->hpal : 0,
1422 FALSE);
1424 This->Flags |= SFLAG_DIBSECTION;
1427 /* Lock the surface */
1428 hr = IWineD3DSurface_LockRect(iface,
1429 &lock,
1430 NULL,
1432 if(FAILED(hr)) {
1433 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1434 /* keep the dib section */
1435 return hr;
1438 if(This->resource.format == WINED3DFMT_P8 ||
1439 This->resource.format == WINED3DFMT_A8P8) {
1440 unsigned int n;
1441 if(This->palette) {
1442 PALETTEENTRY ent[256];
1444 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1445 for (n=0; n<256; n++) {
1446 col[n].rgbRed = ent[n].peRed;
1447 col[n].rgbGreen = ent[n].peGreen;
1448 col[n].rgbBlue = ent[n].peBlue;
1449 col[n].rgbReserved = 0;
1451 } else {
1452 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1454 for (n=0; n<256; n++) {
1455 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1456 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1457 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1458 col[n].rgbReserved = 0;
1462 SetDIBColorTable(This->hDC, 0, 256, col);
1465 *pHDC = This->hDC;
1466 TRACE("returning %p\n",*pHDC);
1467 This->Flags |= SFLAG_DCINUSE;
1469 return WINED3D_OK;
1472 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1473 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1475 TRACE("(%p)->(%p)\n",This,hDC);
1477 if (!(This->Flags & SFLAG_DCINUSE))
1478 return D3DERR_INVALIDCALL;
1480 /* we locked first, so unlock now */
1481 IWineD3DSurface_UnlockRect(iface);
1483 This->Flags &= ~SFLAG_DCINUSE;
1485 return WINED3D_OK;
1488 /* ******************************************************
1489 IWineD3DSurface Internal (No mapping to directx api) parts follow
1490 ****************************************************** */
1492 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) {
1493 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1494 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1496 /* Default values: From the surface */
1497 *format = formatEntry->glFormat;
1498 *internal = formatEntry->glInternal;
1499 *type = formatEntry->glType;
1500 *convert = NO_CONVERSION;
1501 *target_bpp = This->bytesPerPixel;
1503 /* Ok, now look if we have to do any conversion */
1504 switch(This->resource.format) {
1505 case WINED3DFMT_P8:
1506 /* ****************
1507 Paletted Texture
1508 **************** */
1509 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1510 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1512 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1513 *format = GL_RGBA;
1514 *internal = GL_RGBA;
1515 *type = GL_UNSIGNED_BYTE;
1516 *target_bpp = 4;
1517 if(colorkey_active) {
1518 *convert = CONVERT_PALETTED_CK;
1519 } else {
1520 *convert = CONVERT_PALETTED;
1524 break;
1526 case WINED3DFMT_R3G3B2:
1527 /* **********************
1528 GL_UNSIGNED_BYTE_3_3_2
1529 ********************** */
1530 if (colorkey_active) {
1531 /* This texture format will never be used.. So do not care about color keying
1532 up until the point in time it will be needed :-) */
1533 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1535 break;
1537 case WINED3DFMT_R5G6B5:
1538 if (colorkey_active) {
1539 *convert = CONVERT_CK_565;
1540 *format = GL_RGBA;
1541 *internal = GL_RGBA;
1542 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1544 break;
1546 case WINED3DFMT_R8G8B8:
1547 if (colorkey_active) {
1548 *convert = CONVERT_CK_RGB24;
1549 *format = GL_RGBA;
1550 *internal = GL_RGBA;
1551 *type = GL_UNSIGNED_INT_8_8_8_8;
1552 *target_bpp = 4;
1554 break;
1556 case WINED3DFMT_X8R8G8B8:
1557 if (colorkey_active) {
1558 *convert = CONVERT_RGB32_888;
1559 *format = GL_RGBA;
1560 *internal = GL_RGBA;
1561 *type = GL_UNSIGNED_INT_8_8_8_8;
1563 break;
1565 default:
1566 break;
1569 return WINED3D_OK;
1572 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1573 BYTE *source, *dest;
1574 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1576 switch (convert) {
1577 case NO_CONVERSION:
1579 memcpy(dst, src, pitch * height);
1580 break;
1582 case CONVERT_PALETTED:
1583 case CONVERT_PALETTED_CK:
1585 IWineD3DPaletteImpl* pal = surf->palette;
1586 BYTE table[256][4];
1587 unsigned int i;
1588 unsigned int x, y;
1590 if( pal == NULL) {
1591 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1594 if (pal == NULL) {
1595 /* Still no palette? Use the device's palette */
1596 /* Get the surface's palette */
1597 for (i = 0; i < 256; i++) {
1598 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1600 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1601 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1602 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1603 if ((convert == CONVERT_PALETTED_CK) &&
1604 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1605 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1606 /* We should maybe here put a more 'neutral' color than the standard bright purple
1607 one often used by application to prevent the nice purple borders when bi-linear
1608 filtering is on */
1609 table[i][3] = 0x00;
1610 } else {
1611 table[i][3] = 0xFF;
1614 } else {
1615 TRACE("Using surface palette %p\n", pal);
1616 /* Get the surface's palette */
1617 for (i = 0; i < 256; i++) {
1618 table[i][0] = pal->palents[i].peRed;
1619 table[i][1] = pal->palents[i].peGreen;
1620 table[i][2] = pal->palents[i].peBlue;
1621 if ((convert == CONVERT_PALETTED_CK) &&
1622 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1623 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1624 /* We should maybe here put a more 'neutral' color than the standard bright purple
1625 one often used by application to prevent the nice purple borders when bi-linear
1626 filtering is on */
1627 table[i][3] = 0x00;
1628 } else {
1629 table[i][3] = 0xFF;
1634 for (y = 0; y < height; y++)
1636 source = src + pitch * y;
1637 dest = dst + outpitch * y;
1638 /* This is an 1 bpp format, using the width here is fine */
1639 for (x = 0; x < width; x++) {
1640 BYTE color = *source++;
1641 *dest++ = table[color][0];
1642 *dest++ = table[color][1];
1643 *dest++ = table[color][2];
1644 *dest++ = table[color][3];
1648 break;
1650 case CONVERT_CK_565:
1652 /* Converting the 565 format in 5551 packed to emulate color-keying.
1654 Note : in all these conversion, it would be best to average the averaging
1655 pixels to get the color of the pixel that will be color-keyed to
1656 prevent 'color bleeding'. This will be done later on if ever it is
1657 too visible.
1659 Note2: Nvidia documents say that their driver does not support alpha + color keying
1660 on the same surface and disables color keying in such a case
1662 unsigned int x, y;
1663 WORD *Source;
1664 WORD *Dest;
1666 TRACE("Color keyed 565\n");
1668 for (y = 0; y < height; y++) {
1669 Source = (WORD *) (src + y * pitch);
1670 Dest = (WORD *) (dst + y * outpitch);
1671 for (x = 0; x < width; x++ ) {
1672 WORD color = *Source++;
1673 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1674 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1675 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1676 *Dest |= 0x0001;
1678 Dest++;
1682 break;
1684 default:
1685 ERR("Unsupported conversation type %d\n", convert);
1687 return WINED3D_OK;
1690 /* This function is used in case of 8bit paletted textures to upload the palette.
1691 For now it only supports GL_EXT_paletted_texture extension but support for other
1692 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1694 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1695 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1696 IWineD3DPaletteImpl* pal = This->palette;
1697 BYTE table[256][4];
1698 int i;
1700 if (pal == NULL) {
1701 /* Still no palette? Use the device's palette */
1702 /* Get the surface's palette */
1703 for (i = 0; i < 256; i++) {
1704 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1706 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1707 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1708 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1709 if ((convert == CONVERT_PALETTED_CK) &&
1710 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1711 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1712 /* We should maybe here put a more 'neutral' color than the standard bright purple
1713 one often used by application to prevent the nice purple borders when bi-linear
1714 filtering is on */
1715 table[i][3] = 0x00;
1716 } else {
1717 table[i][3] = 0xFF;
1720 } else {
1721 TRACE("Using surface palette %p\n", pal);
1722 /* Get the surface's palette */
1723 for (i = 0; i < 256; i++) {
1724 table[i][0] = pal->palents[i].peRed;
1725 table[i][1] = pal->palents[i].peGreen;
1726 table[i][2] = pal->palents[i].peBlue;
1727 if ((convert == CONVERT_PALETTED_CK) &&
1728 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1729 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1730 /* We should maybe here put a more 'neutral' color than the standard bright purple
1731 one often used by application to prevent the nice purple borders when bi-linear
1732 filtering is on */
1733 table[i][3] = 0x00;
1734 } else {
1735 table[i][3] = 0xFF;
1739 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1742 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1743 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1744 GLenum format, internal, type;
1745 CONVERT_TYPES convert;
1746 int bpp;
1747 int width, pitch, outpitch;
1748 BYTE *mem;
1750 if (This->Flags & SFLAG_INTEXTURE) {
1751 TRACE("Surface already in texture\n");
1752 return WINED3D_OK;
1754 if (This->Flags & SFLAG_DIRTY) {
1755 TRACE("Reloading because surface is dirty\n");
1756 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1757 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1758 /* Reload: vice versa OR */
1759 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1760 /* Also reload: Color key is active AND the color key has changed */
1761 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1762 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1763 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1764 TRACE("Reloading because of color keying\n");
1765 } else {
1766 TRACE("surface isn't dirty\n");
1767 return WINED3D_OK;
1770 This->Flags &= ~SFLAG_DIRTY;
1772 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1773 * These resources are not bound by device size or format restrictions. Because of this,
1774 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1775 * However, these resources can always be created, locked, and copied.
1777 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1779 FIXME("(%p) Operation not supported for scratch textures\n",This);
1780 return WINED3DERR_INVALIDCALL;
1783 if (This->Flags & SFLAG_INPBUFFER) {
1784 if (This->glDescription.level != 0)
1785 FIXME("Surface in texture is only supported for level 0\n");
1786 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1787 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1788 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1789 This->resource.format == WINED3DFMT_DXT5)
1790 FIXME("Format %d not supported\n", This->resource.format);
1791 else {
1792 GLint prevRead;
1794 ENTER_GL();
1796 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1797 vcheckGLcall("glGetIntegerv");
1798 glReadBuffer(GL_BACK);
1799 vcheckGLcall("glReadBuffer");
1801 glCopyTexImage2D(This->glDescription.target,
1802 This->glDescription.level,
1803 This->glDescription.glFormatInternal,
1806 This->currentDesc.Width,
1807 This->currentDesc.Height,
1810 checkGLcall("glCopyTexImage2D");
1811 glReadBuffer(prevRead);
1812 vcheckGLcall("glReadBuffer");
1814 LEAVE_GL();
1816 TRACE("Updating target %d\n", This->glDescription.target);
1817 This->Flags |= SFLAG_INTEXTURE;
1819 return WINED3D_OK;
1822 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1823 This->Flags |= SFLAG_GLCKEY;
1824 This->glCKey = This->SrcBltCKey;
1826 else This->Flags &= ~SFLAG_GLCKEY;
1828 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1830 /* The width is in 'length' not in bytes */
1831 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1832 width = This->currentDesc.Width;
1833 else
1834 width = This->pow2Width;
1836 pitch = IWineD3DSurface_GetPitch(iface);
1838 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1839 int height = This->glRect.bottom - This->glRect.top;
1841 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1842 outpitch = width * bpp;
1843 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1845 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1846 if(!mem) {
1847 ERR("Out of memory %d, %d!\n", outpitch, height);
1848 return WINED3DERR_OUTOFVIDEOMEMORY;
1850 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1852 This->Flags |= SFLAG_CONVERTED;
1853 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1854 d3dfmt_p8_upload_palette(iface, convert);
1855 This->Flags &= ~SFLAG_CONVERTED;
1856 mem = This->resource.allocatedMemory;
1857 } else {
1858 This->Flags &= ~SFLAG_CONVERTED;
1859 mem = This->resource.allocatedMemory;
1862 /* Make sure the correct pitch is used */
1863 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1865 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1866 TRACE("non power of two support\n");
1867 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1868 if (mem) {
1869 surface_upload_data(This, This->pow2Width, This->pow2Height, format, type, mem);
1871 } else {
1872 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1873 if (mem) {
1874 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1878 /* Restore the default pitch */
1879 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1881 if (mem != This->resource.allocatedMemory)
1882 HeapFree(GetProcessHeap(), 0, mem);
1884 #if 0
1886 static unsigned int gen = 0;
1887 char buffer[4096];
1888 ++gen;
1889 if ((gen % 10) == 0) {
1890 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1891 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1894 * debugging crash code
1895 if (gen == 250) {
1896 void** test = NULL;
1897 *test = 0;
1901 #endif
1903 if (!(This->Flags & SFLAG_DONOTFREE)) {
1904 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1905 This->resource.allocatedMemory = NULL;
1908 return WINED3D_OK;
1911 #include <errno.h>
1912 #include <stdio.h>
1913 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1914 FILE* f = NULL;
1915 UINT i, y;
1916 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1917 char *allocatedMemory;
1918 char *textureRow;
1919 IWineD3DSwapChain *swapChain = NULL;
1920 int width, height;
1921 GLuint tmpTexture = 0;
1922 DWORD color;
1923 /*FIXME:
1924 Textures my not be stored in ->allocatedgMemory and a GlTexture
1925 so we should lock the surface before saving a snapshot, or at least check that
1927 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1928 by calling GetTexImage and in compressed form by calling
1929 GetCompressedTexImageARB. Queried compressed images can be saved and
1930 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1931 texture images do not need to be processed by the GL and should
1932 significantly improve texture loading performance relative to uncompressed
1933 images. */
1935 /* Setup the width and height to be the internal texture width and height. */
1936 width = This->pow2Width;
1937 height = This->pow2Height;
1938 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1939 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1941 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1942 /* 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 */
1943 GLint prevRead;
1944 ENTER_GL();
1945 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1946 glEnable(GL_TEXTURE_2D);
1948 glGenTextures(1, &tmpTexture);
1949 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1951 glTexImage2D(GL_TEXTURE_2D,
1953 GL_RGBA,
1954 width,
1955 height,
1956 0/*border*/,
1957 GL_RGBA,
1958 GL_UNSIGNED_INT_8_8_8_8_REV,
1959 NULL);
1961 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1962 vcheckGLcall("glGetIntegerv");
1963 glReadBuffer(GL_BACK);
1964 vcheckGLcall("glReadBuffer");
1965 glCopyTexImage2D(GL_TEXTURE_2D,
1967 GL_RGBA,
1970 width,
1971 height,
1974 checkGLcall("glCopyTexImage2D");
1975 glReadBuffer(prevRead);
1976 LEAVE_GL();
1978 } else { /* bind the real texture */
1979 IWineD3DSurface_PreLoad(iface);
1981 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1982 ENTER_GL();
1983 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1984 glGetTexImage(GL_TEXTURE_2D,
1985 This->glDescription.level,
1986 GL_RGBA,
1987 GL_UNSIGNED_INT_8_8_8_8_REV,
1988 allocatedMemory);
1989 checkGLcall("glTexImage2D");
1990 if (tmpTexture) {
1991 glBindTexture(GL_TEXTURE_2D, 0);
1992 glDeleteTextures(1, &tmpTexture);
1994 LEAVE_GL();
1996 f = fopen(filename, "w+");
1997 if (NULL == f) {
1998 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1999 return WINED3DERR_INVALIDCALL;
2001 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
2002 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2003 /* TGA header */
2004 fputc(0,f);
2005 fputc(0,f);
2006 fputc(2,f);
2007 fputc(0,f);
2008 fputc(0,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 /* short width*/
2017 fwrite(&width,2,1,f);
2018 /* short height */
2019 fwrite(&height,2,1,f);
2020 /* format rgba */
2021 fputc(0x20,f);
2022 fputc(0x28,f);
2023 /* raw data */
2024 /* 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*/
2025 if(swapChain)
2026 textureRow = allocatedMemory + (width * (height - 1) *4);
2027 else
2028 textureRow = allocatedMemory;
2029 for (y = 0 ; y < height; y++) {
2030 for (i = 0; i < width; i++) {
2031 color = *((DWORD*)textureRow);
2032 fputc((color >> 16) & 0xFF, f); /* B */
2033 fputc((color >> 8) & 0xFF, f); /* G */
2034 fputc((color >> 0) & 0xFF, f); /* R */
2035 fputc((color >> 24) & 0xFF, f); /* A */
2036 textureRow += 4;
2038 /* take two rows of the pointer to the texture memory */
2039 if(swapChain)
2040 (textureRow-= width << 3);
2043 TRACE("Closing file\n");
2044 fclose(f);
2046 if(swapChain) {
2047 IWineD3DSwapChain_Release(swapChain);
2049 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2050 return WINED3D_OK;
2053 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2054 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2055 This->Flags &= ~SFLAG_DIRTY;
2056 This->dirtyRect.left = This->currentDesc.Width;
2057 This->dirtyRect.top = This->currentDesc.Height;
2058 This->dirtyRect.right = 0;
2059 This->dirtyRect.bottom = 0;
2060 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2061 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2062 return WINED3D_OK;
2066 * Slightly inefficient way to handle multiple dirty rects but it works :)
2068 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2069 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2070 IWineD3DBaseTexture *baseTexture = NULL;
2071 This->Flags |= SFLAG_DIRTY;
2072 if (NULL != pDirtyRect) {
2073 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2074 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2075 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2076 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2077 } else {
2078 This->dirtyRect.left = 0;
2079 This->dirtyRect.top = 0;
2080 This->dirtyRect.right = This->currentDesc.Width;
2081 This->dirtyRect.bottom = This->currentDesc.Height;
2083 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2084 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2085 /* if the container is a basetexture then mark it dirty. */
2086 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2087 TRACE("Passing to conatiner\n");
2088 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2089 IWineD3DBaseTexture_Release(baseTexture);
2091 return WINED3D_OK;
2094 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2095 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2097 TRACE("This %p, container %p\n", This, container);
2099 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2101 TRACE("Setting container to %p from %p\n", container, This->container);
2102 This->container = container;
2104 return WINED3D_OK;
2107 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2108 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2109 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2111 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2112 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2113 return WINED3DERR_INVALIDCALL;
2116 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2117 if (format == WINED3DFMT_UNKNOWN) {
2118 This->resource.size = 0;
2119 } else if (format == WINED3DFMT_DXT1) {
2120 /* DXT1 is half byte per pixel */
2121 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2123 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2124 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2125 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2126 } else {
2127 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2128 This->resource.size *= This->pow2Height;
2132 /* Setup some glformat defaults */
2133 This->glDescription.glFormat = formatEntry->glFormat;
2134 This->glDescription.glFormatInternal = formatEntry->glInternal;
2135 This->glDescription.glType = formatEntry->glType;
2137 if (format != WINED3DFMT_UNKNOWN) {
2138 This->bytesPerPixel = formatEntry->bpp;
2139 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2140 } else {
2141 This->bytesPerPixel = 0;
2142 This->pow2Size = 0;
2145 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2147 This->resource.format = format;
2149 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);
2151 return WINED3D_OK;
2154 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2155 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2157 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2158 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2159 ERR("Not supported on render targets\n");
2160 return WINED3DERR_INVALIDCALL;
2163 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2164 WARN("Surface is locked or the HDC is in use\n");
2165 return WINED3DERR_INVALIDCALL;
2168 if(Mem && Mem != This->resource.allocatedMemory) {
2170 /* Do I have to copy the old surface content? */
2171 if(This->Flags & SFLAG_DIBSECTION) {
2172 /* Release the DC. No need to hold the critical section for the update
2173 * Thread because this thread runs only on front buffers, but this method
2174 * fails for render targets in the check above.
2176 SelectObject(This->hDC, This->dib.holdbitmap);
2177 DeleteDC(This->hDC);
2178 /* Release the DIB section */
2179 DeleteObject(This->dib.DIBsection);
2180 This->dib.bitmap_data = NULL;
2181 This->resource.allocatedMemory = NULL;
2182 This->hDC = NULL;
2183 This->Flags &= ~SFLAG_DIBSECTION;
2184 } else if(!(This->Flags & SFLAG_USERPTR)) {
2185 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2187 This->resource.allocatedMemory = Mem;
2188 This->Flags |= SFLAG_USERPTR;
2189 } else if(This->Flags & SFLAG_USERPTR) {
2190 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2191 This->resource.allocatedMemory = NULL;
2192 This->Flags &= ~SFLAG_USERPTR;
2194 return WINED3D_OK;
2197 /* TODO: replace this function with context management routines */
2198 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2199 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2201 if(inPBuffer) {
2202 This->Flags |= SFLAG_INPBUFFER;
2203 } else {
2204 This->Flags &= ~SFLAG_INPBUFFER;
2207 if(inTexture) {
2208 This->Flags |= SFLAG_INTEXTURE;
2209 } else {
2210 This->Flags &= ~SFLAG_INTEXTURE;
2213 return WINED3D_OK;
2216 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2217 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2218 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2219 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2221 /* Flipping is only supported on RenderTargets */
2222 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2224 if(override) {
2225 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2226 * FIXME("(%p) Target override is not supported by now\n", This);
2227 * Additionally, it isn't really possible to support triple-buffering
2228 * properly on opengl at all
2232 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2233 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2236 /* Not called from the VTable */
2237 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2238 WINED3DRECT rect;
2239 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2240 IWineD3DSwapChainImpl *swapchain = NULL;
2241 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2242 BOOL SrcOK = TRUE;
2244 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2246 /* Get the swapchain. One of the surfaces has to be a primary surface */
2247 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2248 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2249 else if(Src) {
2250 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2251 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2252 else return WINED3DERR_INVALIDCALL;
2253 } else {
2254 swapchain = NULL;
2257 if (DestRect) {
2258 rect.x1 = DestRect->left;
2259 rect.y1 = DestRect->top;
2260 rect.x2 = DestRect->right;
2261 rect.y2 = DestRect->bottom;
2262 } else {
2263 rect.x1 = 0;
2264 rect.y1 = 0;
2265 rect.x2 = This->currentDesc.Width;
2266 rect.y2 = This->currentDesc.Height;
2269 /* Half-life does a Blt from the back buffer to the front buffer,
2270 * Full surface size, no flags... Use present instead
2272 if(Src)
2274 /* First, check if we can do a Flip */
2276 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2277 if( SrcRect ) {
2278 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2279 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2280 SrcOK = TRUE;
2282 } else {
2283 SrcOK = TRUE;
2286 /* Check the Destination rect and the surface sizes */
2287 if(SrcOK &&
2288 (rect.x1 == 0) && (rect.y1 == 0) &&
2289 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2290 (This->currentDesc.Width == Src->currentDesc.Width) &&
2291 (This->currentDesc.Height == Src->currentDesc.Height)) {
2292 /* These flags are unimportant for the flag check, remove them */
2294 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2295 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2297 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2299 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2300 * take very long, while a flip is fast.
2301 * This applies to Half-Life, which does such Blts every time it finished
2302 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2303 * menu. This is also used by all apps when they do windowed rendering
2305 * The problem is that flipping is not really the same as copying. After a
2306 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2307 * untouched. Therefore it's necessary to override the swap effect
2308 * and to set it back after the flip.
2311 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2313 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2314 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2315 NULL, NULL, 0, NULL);
2317 swapchain->presentParms.SwapEffect = orig_swap;
2319 return WINED3D_OK;
2324 /* Blt from texture to rendertarget? */
2325 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2326 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2328 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2329 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2330 float glTexCoord[4];
2331 DWORD oldCKey;
2332 DDCOLORKEY oldBltCKey = {0,0};
2333 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2334 GLint oldStencil, oldNVRegisterCombiners = 0;
2335 GLint alphafunc;
2336 GLclampf alpharef;
2337 RECT SourceRectangle;
2338 GLint oldDraw;
2340 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2342 if(SrcRect) {
2343 SourceRectangle.left = SrcRect->left;
2344 SourceRectangle.right = SrcRect->right;
2345 SourceRectangle.top = SrcRect->top;
2346 SourceRectangle.bottom = SrcRect->bottom;
2347 } else {
2348 SourceRectangle.left = 0;
2349 SourceRectangle.right = Src->currentDesc.Width;
2350 SourceRectangle.top = 0;
2351 SourceRectangle.bottom = Src->currentDesc.Height;
2354 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2355 /* Fall back to software */
2356 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2357 SourceRectangle.left, SourceRectangle.top,
2358 SourceRectangle.right, SourceRectangle.bottom);
2359 return WINED3DERR_INVALIDCALL;
2362 /* Color keying: Check if we have to do a color keyed blt,
2363 * and if not check if a color key is activated.
2365 oldCKey = Src->CKeyFlags;
2366 if(!(Flags & DDBLT_KEYSRC) &&
2367 Src->CKeyFlags & DDSD_CKSRCBLT) {
2368 /* Ok, the surface has a color key, but we shall not use it -
2369 * Deactivate it for now, LoadTexture will catch this
2371 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2374 /* Color keying */
2375 if(Flags & DDBLT_KEYDEST) {
2376 oldBltCKey = This->SrcBltCKey;
2377 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2378 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2380 This->SrcBltCKey = This->DestBltCKey;
2381 } else if (Flags & DDBLT_KEYSRC)
2382 oldBltCKey = This->SrcBltCKey;
2384 /* Now load the surface */
2385 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2387 ENTER_GL();
2389 /* Save all the old stuff until we have a proper opengl state manager */
2390 oldLight = glIsEnabled(GL_LIGHTING);
2391 oldFog = glIsEnabled(GL_FOG);
2392 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2393 oldBlend = glIsEnabled(GL_BLEND);
2394 oldCull = glIsEnabled(GL_CULL_FACE);
2395 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2396 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2398 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2399 oldNVRegisterCombiners = glIsEnabled(GL_REGISTER_COMBINERS_NV);
2402 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2403 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2404 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2405 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2407 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2408 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2409 TRACE("Drawing to front buffer\n");
2410 glDrawBuffer(GL_FRONT);
2411 checkGLcall("glDrawBuffer GL_FRONT");
2414 /* Unbind the old texture */
2415 glBindTexture(GL_TEXTURE_2D, 0);
2416 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
2418 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2419 /* We use texture unit 0 for blts */
2420 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2421 checkGLcall("glActiveTextureARB");
2422 } else {
2423 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2426 /* Disable some fancy graphics effects */
2427 glDisable(GL_LIGHTING);
2428 checkGLcall("glDisable GL_LIGHTING");
2429 glDisable(GL_DEPTH_TEST);
2430 checkGLcall("glDisable GL_DEPTH_TEST");
2431 glDisable(GL_FOG);
2432 checkGLcall("glDisable GL_FOG");
2433 glDisable(GL_BLEND);
2434 checkGLcall("glDisable GL_BLEND");
2435 glDisable(GL_CULL_FACE);
2436 checkGLcall("glDisable GL_CULL_FACE");
2437 glDisable(GL_STENCIL_TEST);
2438 checkGLcall("glDisable GL_STENCIL_TEST");
2439 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2440 glDisable(GL_REGISTER_COMBINERS_NV);
2441 checkGLcall("glDisable GL_REGISTER_COMBINERS_NV");
2444 /* Ok, we need 2d textures, but not 1D or 3D */
2445 glDisable(GL_TEXTURE_1D);
2446 checkGLcall("glDisable GL_TEXTURE_1D");
2447 glEnable(GL_TEXTURE_2D);
2448 checkGLcall("glEnable GL_TEXTURE_2D");
2449 glDisable(GL_TEXTURE_3D);
2450 checkGLcall("glDisable GL_TEXTURE_3D");
2452 /* Bind the texture */
2453 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2454 checkGLcall("glBindTexture");
2456 glEnable(GL_SCISSOR_TEST);
2458 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2460 /* No filtering for blts */
2461 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2462 GL_NEAREST);
2463 checkGLcall("glTexParameteri");
2464 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2465 GL_NEAREST);
2466 checkGLcall("glTexParameteri");
2467 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2468 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2469 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2470 checkGLcall("glTexEnvi");
2472 /* This is for color keying */
2473 if(Flags & DDBLT_KEYSRC) {
2474 glEnable(GL_ALPHA_TEST);
2475 checkGLcall("glEnable GL_ALPHA_TEST");
2476 glAlphaFunc(GL_NOTEQUAL, 0.0);
2477 checkGLcall("glAlphaFunc\n");
2478 } else {
2479 glDisable(GL_ALPHA_TEST);
2480 checkGLcall("glDisable GL_ALPHA_TEST");
2483 /* Draw a textured quad
2485 myDevice->last_was_rhw = TRUE;
2486 /* Apply the projection matrix, it sets up orthogonal projection due to last_was_rhw */
2487 StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock);
2488 StateTable[STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))].apply(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), myDevice->stateBlock);
2489 /* That will reapply the projection matrix too */
2490 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL);
2492 glBegin(GL_QUADS);
2494 glColor3d(1.0f, 1.0f, 1.0f);
2495 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2496 glVertex3f(rect.x1,
2497 rect.y1,
2498 0.0);
2500 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2501 glVertex3f(rect.x1, rect.y2, 0.0);
2503 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2504 glVertex3f(rect.x2,
2505 rect.y2,
2506 0.0);
2508 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2509 glVertex3f(rect.x2,
2510 rect.y1,
2511 0.0);
2512 glEnd();
2513 checkGLcall("glEnd");
2515 /* Unbind the texture */
2516 glBindTexture(GL_TEXTURE_2D, 0);
2517 checkGLcall("glEnable glBindTexture");
2519 /* Restore the old settings */
2520 if(oldLight) {
2521 glEnable(GL_LIGHTING);
2522 checkGLcall("glEnable GL_LIGHTING");
2524 if(oldFog) {
2525 glEnable(GL_FOG);
2526 checkGLcall("glEnable GL_FOG");
2528 if(oldDepth) {
2529 glEnable(GL_DEPTH_TEST);
2530 checkGLcall("glEnable GL_DEPTH_TEST");
2532 if(oldBlend) {
2533 glEnable(GL_BLEND);
2534 checkGLcall("glEnable GL_BLEND");
2536 if(oldCull) {
2537 glEnable(GL_CULL_FACE);
2538 checkGLcall("glEnable GL_CULL_FACE");
2540 if(oldStencil) {
2541 glEnable(GL_STENCIL_TEST);
2542 checkGLcall("glEnable GL_STENCIL_TEST");
2544 if(!oldAlpha) {
2545 glDisable(GL_ALPHA_TEST);
2546 checkGLcall("glDisable GL_ALPHA_TEST");
2547 } else {
2548 glEnable(GL_ALPHA_TEST);
2549 checkGLcall("glEnable GL_ALPHA_TEST");
2551 if (GL_SUPPORT(NV_REGISTER_COMBINERS) && oldNVRegisterCombiners) {
2552 glEnable(GL_REGISTER_COMBINERS_NV);
2553 checkGLcall("glEnable GL_REGISTER_COMBINERS_NV");
2556 glAlphaFunc(alphafunc, alpharef);
2557 checkGLcall("glAlphaFunc\n");
2559 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2560 glDrawBuffer(oldDraw);
2563 /* Restore the color key flags */
2564 if(oldCKey != Src->CKeyFlags) {
2565 Src->CKeyFlags = oldCKey;
2568 /* Restore the old color key */
2569 if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
2570 This->SrcBltCKey = oldBltCKey;
2572 LEAVE_GL();
2574 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2575 This->Flags |= SFLAG_GLDIRTY;
2577 return WINED3D_OK;
2581 /* Blt from rendertarget to texture? */
2582 if( (SrcSurface == swapchain->frontBuffer) ||
2583 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2584 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2585 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2586 UINT row;
2587 WINED3DRECT srect;
2588 float xrel, yrel;
2590 TRACE("Blt from rendertarget to texture\n");
2592 /* Call preload for the surface to make sure it isn't dirty */
2593 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2595 if(SrcRect) {
2596 srect.x1 = SrcRect->left;
2597 srect.y1 = SrcRect->top;
2598 srect.x2 = SrcRect->right;
2599 srect.y2 = SrcRect->bottom;
2600 } else {
2601 srect.x1 = 0;
2602 srect.y1 = 0;
2603 srect.x2 = Src->currentDesc.Width;
2604 srect.y2 = Src->currentDesc.Height;
2607 ENTER_GL();
2609 /* Bind the target texture */
2610 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2611 checkGLcall("glBindTexture");
2612 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2613 glReadBuffer(GL_BACK);
2614 } else {
2615 glReadBuffer(GL_FRONT);
2617 checkGLcall("glReadBuffer");
2619 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2620 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2622 /* I have to process this row by row to swap the image,
2623 * otherwise it would be upside down, so streching in y direction
2624 * doesn't cost extra time
2626 * However, streching in x direction can be avoided if not necessary
2628 for(row = rect.y1; row < rect.y2; row++) {
2629 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2630 /* Well, that stuff works, but it's very slow.
2631 * find a better way instead
2633 UINT col;
2634 for(col = rect.x1; col < rect.x2; col++) {
2635 glCopyTexSubImage2D(GL_TEXTURE_2D,
2636 0, /* level */
2637 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2638 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2639 1, 1);
2641 } else {
2642 glCopyTexSubImage2D(GL_TEXTURE_2D,
2643 0, /* level */
2644 rect.x1, rect.y2 + rect.y1 - row - 1, /* xoffset, yoffset */
2645 srect.x1, row - rect.y1,
2646 rect.x2-rect.x1, 1);
2650 vcheckGLcall("glCopyTexSubImage2D");
2651 LEAVE_GL();
2653 if(!(This->Flags & SFLAG_DONOTFREE)) {
2654 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2655 This->resource.allocatedMemory = NULL;
2656 } else {
2657 This->Flags |= SFLAG_GLDIRTY;
2660 return WINED3D_OK;
2665 if (Flags & DDBLT_COLORFILL) {
2666 /* This is easy to handle for the D3D Device... */
2667 DWORD color;
2668 IWineD3DSwapChainImpl *implSwapChain;
2670 TRACE("Colorfill\n");
2672 /* The color as given in the Blt function is in the format of the frame-buffer...
2673 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2675 if (This->resource.format == WINED3DFMT_P8) {
2676 if (This->palette) {
2677 color = ((0xFF000000) |
2678 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2679 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2680 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2681 } else {
2682 color = 0xFF000000;
2685 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2686 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2687 color = 0xFFFFFFFF;
2688 } else {
2689 color = ((0xFF000000) |
2690 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2691 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2692 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2695 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2696 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2697 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2699 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2700 color = DDBltFx->u5.dwFillColor;
2702 else {
2703 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2704 return WINED3DERR_INVALIDCALL;
2707 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2708 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2709 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2710 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2711 glDrawBuffer(GL_BACK);
2712 checkGLcall("glDrawBuffer(GL_BACK)");
2714 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2715 glDrawBuffer(GL_FRONT);
2716 checkGLcall("glDrawBuffer(GL_FRONT)");
2718 else {
2719 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2720 return WINED3DERR_INVALIDCALL;
2723 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2725 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2726 1 /* Number of rectangles */,
2727 &rect,
2728 WINED3DCLEAR_TARGET,
2729 color,
2730 0.0 /* Z */,
2731 0 /* Stencil */);
2733 /* Restore the original draw buffer */
2734 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2735 glDrawBuffer(GL_BACK);
2736 vcheckGLcall("glDrawBuffer");
2739 return WINED3D_OK;
2742 /* Default: Fall back to the generic blt */
2743 return WINED3DERR_INVALIDCALL;
2746 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2747 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2748 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2749 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2750 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2752 /* Special cases for RenderTargets */
2753 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2754 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2755 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2758 /* For the rest call the X11 surface implementation.
2759 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2760 * other Blts are rather rare
2762 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2765 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2766 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2767 TRACE("(%p)->(%x)\n", This, Flags);
2769 switch (Flags)
2771 case DDGBS_CANBLT:
2772 case DDGBS_ISBLTDONE:
2773 return DD_OK;
2775 default:
2776 return DDERR_INVALIDPARAMS;
2780 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2781 /* XXX: DDERR_INVALIDSURFACETYPE */
2783 TRACE("(%p)->(%08x)\n",iface,Flags);
2784 switch (Flags) {
2785 case DDGFS_CANFLIP:
2786 case DDGFS_ISFLIPDONE:
2787 return DD_OK;
2789 default:
2790 return DDERR_INVALIDPARAMS;
2794 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2795 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2796 TRACE("(%p)\n", This);
2798 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2801 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2802 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2803 TRACE("(%p)\n", This);
2805 /* So far we don't lose anything :) */
2806 This->Flags &= ~SFLAG_LOST;
2807 return WINED3D_OK;
2810 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2811 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2812 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2813 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2815 /* Special cases for RenderTargets */
2816 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2817 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2819 RECT SrcRect, DstRect;
2820 DWORD Flags=0;
2822 if(rsrc) {
2823 SrcRect.left = rsrc->left;
2824 SrcRect.top= rsrc->top;
2825 SrcRect.bottom = rsrc->bottom;
2826 SrcRect.right = rsrc->right;
2827 } else {
2828 SrcRect.left = 0;
2829 SrcRect.top = 0;
2830 SrcRect.right = srcImpl->currentDesc.Width;
2831 SrcRect.bottom = srcImpl->currentDesc.Height;
2834 DstRect.left = dstx;
2835 DstRect.top=dsty;
2836 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2837 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2839 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2840 if(trans & DDBLTFAST_SRCCOLORKEY)
2841 Flags |= DDBLT_KEYSRC;
2842 if(trans & DDBLTFAST_DESTCOLORKEY)
2843 Flags |= DDBLT_KEYDEST;
2844 if(trans & DDBLTFAST_WAIT)
2845 Flags |= DDBLT_WAIT;
2846 if(trans & DDBLTFAST_DONOTWAIT)
2847 Flags |= DDBLT_DONOTWAIT;
2849 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2853 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2856 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2857 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2858 TRACE("(%p)->(%p)\n", This, Pal);
2860 *Pal = (IWineD3DPalette *) This->palette;
2861 return DD_OK;
2864 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2865 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2866 RGBQUAD col[256];
2867 IWineD3DPaletteImpl *pal = This->palette;
2868 unsigned int n;
2869 TRACE("(%p)\n", This);
2871 if(This->resource.format == WINED3DFMT_P8 ||
2872 This->resource.format == WINED3DFMT_A8P8)
2874 TRACE("Dirtifying surface\n");
2875 This->Flags |= SFLAG_DIRTY;
2878 if(This->Flags & SFLAG_DIBSECTION) {
2879 TRACE("(%p): Updating the hdc's palette\n", This);
2880 for (n=0; n<256; n++) {
2881 if(pal) {
2882 col[n].rgbRed = pal->palents[n].peRed;
2883 col[n].rgbGreen = pal->palents[n].peGreen;
2884 col[n].rgbBlue = pal->palents[n].peBlue;
2885 } else {
2886 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2887 /* Use the default device palette */
2888 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2889 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2890 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2892 col[n].rgbReserved = 0;
2894 SetDIBColorTable(This->hDC, 0, 256, col);
2897 return WINED3D_OK;
2900 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2901 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2902 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2903 TRACE("(%p)->(%p)\n", This, Pal);
2905 if(This->palette != NULL)
2906 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2907 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2909 if(PalImpl != NULL) {
2910 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2911 /* Set the device's main palette if the palette
2912 * wasn't a primary palette before
2914 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2915 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2916 unsigned int i;
2918 for(i=0; i < 256; i++) {
2919 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2923 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2926 This->palette = PalImpl;
2928 return IWineD3DSurface_RealizePalette(iface);
2931 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2932 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2933 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
2935 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2936 FIXME(" colorkey value not supported (%08x) !\n", Flags);
2937 return DDERR_INVALIDPARAMS;
2940 /* Dirtify the surface, but only if a key was changed */
2941 if(CKey) {
2942 switch (Flags & ~DDCKEY_COLORSPACE) {
2943 case DDCKEY_DESTBLT:
2944 This->DestBltCKey = *CKey;
2945 This->CKeyFlags |= DDSD_CKDESTBLT;
2946 break;
2948 case DDCKEY_DESTOVERLAY:
2949 This->DestOverlayCKey = *CKey;
2950 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2951 break;
2953 case DDCKEY_SRCOVERLAY:
2954 This->SrcOverlayCKey = *CKey;
2955 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2956 break;
2958 case DDCKEY_SRCBLT:
2959 This->SrcBltCKey = *CKey;
2960 This->CKeyFlags |= DDSD_CKSRCBLT;
2961 break;
2964 else {
2965 switch (Flags & ~DDCKEY_COLORSPACE) {
2966 case DDCKEY_DESTBLT:
2967 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2968 break;
2970 case DDCKEY_DESTOVERLAY:
2971 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2972 break;
2974 case DDCKEY_SRCOVERLAY:
2975 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2976 break;
2978 case DDCKEY_SRCBLT:
2979 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2980 break;
2984 return WINED3D_OK;
2987 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2988 /** Check against the maximum texture sizes supported by the video card **/
2989 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2991 TRACE("%p\n", This);
2992 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2993 /* one of three options
2994 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)
2995 2: Set the texture to the maxium size (bad idea)
2996 3: WARN and return WINED3DERR_NOTAVAILABLE;
2997 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.
2999 WARN("(%p) Creating an oversized surface\n", This);
3000 This->Flags |= SFLAG_OVERSIZE;
3002 /* This will be initialized on the first blt */
3003 This->glRect.left = 0;
3004 This->glRect.top = 0;
3005 This->glRect.right = 0;
3006 This->glRect.bottom = 0;
3007 } else {
3008 /* No oversize, gl rect is the full texture size */
3009 This->Flags &= ~SFLAG_OVERSIZE;
3010 This->glRect.left = 0;
3011 This->glRect.top = 0;
3012 This->glRect.right = This->pow2Width;
3013 This->glRect.bottom = This->pow2Height;
3016 return WINED3D_OK;
3019 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3020 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3021 DWORD ret;
3022 TRACE("(%p)\n", This);
3024 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3025 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3026 ie pitch = (width/4) * bytes per block */
3027 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3028 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3029 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3030 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3031 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3032 else {
3033 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3034 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3035 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3036 } else {
3037 ret = This->bytesPerPixel * This->pow2Width;
3039 /* Surfaces are 32 bit aligned */
3040 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3042 TRACE("(%p) Returning %d\n", This, ret);
3043 return ret;
3046 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3047 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3049 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3051 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3053 TRACE("(%p): Not an overlay surface\n", This);
3054 return DDERR_NOTAOVERLAYSURFACE;
3057 return WINED3D_OK;
3060 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3061 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3063 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3065 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3067 TRACE("(%p): Not an overlay surface\n", This);
3068 return DDERR_NOTAOVERLAYSURFACE;
3071 return WINED3D_OK;
3074 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3075 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3076 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3078 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3080 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3082 TRACE("(%p): Not an overlay surface\n", This);
3083 return DDERR_NOTAOVERLAYSURFACE;
3086 return WINED3D_OK;
3089 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3090 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3091 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3092 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3094 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3096 TRACE("(%p): Not an overlay surface\n", This);
3097 return DDERR_NOTAOVERLAYSURFACE;
3100 return WINED3D_OK;
3103 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3105 /* IUnknown */
3106 IWineD3DSurfaceImpl_QueryInterface,
3107 IWineD3DSurfaceImpl_AddRef,
3108 IWineD3DSurfaceImpl_Release,
3109 /* IWineD3DResource */
3110 IWineD3DSurfaceImpl_GetParent,
3111 IWineD3DSurfaceImpl_GetDevice,
3112 IWineD3DSurfaceImpl_SetPrivateData,
3113 IWineD3DSurfaceImpl_GetPrivateData,
3114 IWineD3DSurfaceImpl_FreePrivateData,
3115 IWineD3DSurfaceImpl_SetPriority,
3116 IWineD3DSurfaceImpl_GetPriority,
3117 IWineD3DSurfaceImpl_PreLoad,
3118 IWineD3DSurfaceImpl_GetType,
3119 /* IWineD3DSurface */
3120 IWineD3DSurfaceImpl_GetContainer,
3121 IWineD3DSurfaceImpl_GetDesc,
3122 IWineD3DSurfaceImpl_LockRect,
3123 IWineD3DSurfaceImpl_UnlockRect,
3124 IWineD3DSurfaceImpl_GetDC,
3125 IWineD3DSurfaceImpl_ReleaseDC,
3126 IWineD3DSurfaceImpl_Flip,
3127 IWineD3DSurfaceImpl_Blt,
3128 IWineD3DSurfaceImpl_GetBltStatus,
3129 IWineD3DSurfaceImpl_GetFlipStatus,
3130 IWineD3DSurfaceImpl_IsLost,
3131 IWineD3DSurfaceImpl_Restore,
3132 IWineD3DSurfaceImpl_BltFast,
3133 IWineD3DSurfaceImpl_GetPalette,
3134 IWineD3DSurfaceImpl_SetPalette,
3135 IWineD3DSurfaceImpl_RealizePalette,
3136 IWineD3DSurfaceImpl_SetColorKey,
3137 IWineD3DSurfaceImpl_GetPitch,
3138 IWineD3DSurfaceImpl_SetMem,
3139 IWineD3DSurfaceImpl_SetOverlayPosition,
3140 IWineD3DSurfaceImpl_GetOverlayPosition,
3141 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3142 IWineD3DSurfaceImpl_UpdateOverlay,
3143 /* Internal use: */
3144 IWineD3DSurfaceImpl_CleanDirtyRect,
3145 IWineD3DSurfaceImpl_AddDirtyRect,
3146 IWineD3DSurfaceImpl_LoadTexture,
3147 IWineD3DSurfaceImpl_SaveSnapshot,
3148 IWineD3DSurfaceImpl_SetContainer,
3149 IWineD3DSurfaceImpl_SetPBufferState,
3150 IWineD3DSurfaceImpl_SetGlTextureDesc,
3151 IWineD3DSurfaceImpl_GetGlDesc,
3152 IWineD3DSurfaceImpl_GetData,
3153 IWineD3DSurfaceImpl_SetFormat,
3154 IWineD3DSurfaceImpl_PrivateSetup