rpcrt4: Implement NdrSimpleType{Marshall,Unmarshall}.
[wine/wine-gecko.git] / dlls / wined3d / surface.c
blobca9900a9f5cc02e1ac029fd877f769d01ab0ce1d
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 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
828 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
829 * changed
831 if(!(This->Flags & SFLAG_DYNLOCK)) {
832 This->lockCount++;
833 /* MAXLOCKCOUNT is defined in wined3d_private.h */
834 if(This->lockCount > MAXLOCKCOUNT) {
835 TRACE("Surface is locked regularily, not freeing the system memory copy any more\n");
836 This->Flags |= SFLAG_DYNLOCK;
840 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
842 This->Flags |= SFLAG_LOCKED;
843 return WINED3D_OK;
846 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
847 GLint prev_store;
848 GLint prev_rasterpos[4];
849 GLint skipBytes = 0;
850 BOOL storechanged = FALSE;
851 GLint fmt, type;
852 void *mem;
854 glDisable(GL_TEXTURE_2D);
855 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
856 glDisable(GL_TEXTURE_1D);
857 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
859 glFlush();
860 vcheckGLcall("glFlush");
861 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
862 vcheckGLcall("glIntegerv");
863 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
864 vcheckGLcall("glIntegerv");
865 glPixelZoom(1.0, -1.0);
866 vcheckGLcall("glPixelZoom");
868 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
869 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
870 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
872 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
873 vcheckGLcall("glRasterPos2f");
875 /* Some drivers(radeon dri, others?) don't like exceptions during
876 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
877 * after ReleaseDC. Reading it will cause an exception, which x11drv will
878 * catch to put the dib section in InSync mode, which leads to a crash
879 * and a blocked x server on my radeon card.
881 * The following lines read the dib section so it is put in inSync mode
882 * before glDrawPixels is called and the crash is prevented. There won't
883 * be any interfering gdi accesses, because UnlockRect is called from
884 * ReleaseDC, and the app won't use the dc any more afterwards.
886 if(This->Flags & SFLAG_DIBSECTION) {
887 volatile BYTE read;
888 read = This->resource.allocatedMemory[0];
891 switch (This->resource.format) {
892 /* No special care needed */
893 case WINED3DFMT_A4R4G4B4:
894 case WINED3DFMT_R5G6B5:
895 case WINED3DFMT_A1R5G5B5:
896 case WINED3DFMT_R8G8B8:
897 type = This->glDescription.glType;
898 fmt = This->glDescription.glFormat;
899 mem = This->resource.allocatedMemory;
900 break;
902 case WINED3DFMT_X4R4G4B4:
904 int size;
905 unsigned short *data;
906 data = (unsigned short *)This->resource.allocatedMemory;
907 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
908 while(size > 0) {
909 *data |= 0xF000;
910 data++;
911 size--;
913 type = This->glDescription.glType;
914 fmt = This->glDescription.glFormat;
915 mem = This->resource.allocatedMemory;
917 break;
919 case WINED3DFMT_X1R5G5B5:
921 int size;
922 unsigned short *data;
923 data = (unsigned short *)This->resource.allocatedMemory;
924 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
925 while(size > 0) {
926 *data |= 0x8000;
927 data++;
928 size--;
930 type = This->glDescription.glType;
931 fmt = This->glDescription.glFormat;
932 mem = This->resource.allocatedMemory;
934 break;
936 case WINED3DFMT_X8R8G8B8:
938 /* make sure the X byte is set to alpha on, since it
939 could be any random value. This fixes the intro movie in Pirates! */
940 int size;
941 unsigned int *data;
942 data = (unsigned int *)This->resource.allocatedMemory;
943 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
944 while(size > 0) {
945 *data |= 0xFF000000;
946 data++;
947 size--;
950 /* Fall through */
952 case WINED3DFMT_A8R8G8B8:
954 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
955 vcheckGLcall("glPixelStorei");
956 storechanged = TRUE;
957 type = This->glDescription.glType;
958 fmt = This->glDescription.glFormat;
959 mem = This->resource.allocatedMemory;
961 break;
963 case WINED3DFMT_A2R10G10B10:
965 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
966 vcheckGLcall("glPixelStorei");
967 storechanged = TRUE;
968 type = This->glDescription.glType;
969 fmt = This->glDescription.glFormat;
970 mem = This->resource.allocatedMemory;
972 break;
974 case WINED3DFMT_P8:
976 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
977 int height = This->glRect.bottom - This->glRect.top;
978 type = GL_UNSIGNED_BYTE;
979 fmt = GL_RGBA;
981 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
982 if(!mem) {
983 ERR("Out of memory\n");
984 return;
986 d3dfmt_convert_surface(This->resource.allocatedMemory,
987 mem,
988 pitch,
989 pitch,
990 height,
991 pitch * 4,
992 CONVERT_PALETTED,
993 This);
995 break;
997 default:
998 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
1000 /* Give it a try */
1001 type = This->glDescription.glType;
1002 fmt = This->glDescription.glFormat;
1003 mem = This->resource.allocatedMemory;
1006 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1007 (This->lockedRect.bottom - This->lockedRect.top)-1,
1008 fmt, type,
1009 mem);
1010 checkGLcall("glDrawPixels");
1011 glPixelZoom(1.0,1.0);
1012 vcheckGLcall("glPixelZoom");
1014 glRasterPos3iv(&prev_rasterpos[0]);
1015 vcheckGLcall("glRasterPos3iv");
1017 /* Reset to previous pack row length */
1018 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1019 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1020 if(storechanged) {
1021 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
1022 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1025 if(mem != This->resource.allocatedMemory) HeapFree(GetProcessHeap(), 0, mem);
1026 return;
1029 static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
1030 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1031 float glTexCoord[4];
1033 glTexCoord[0] = 0.0; /* left */
1034 glTexCoord[1] = (float) This->currentDesc.Width / (float) This->pow2Width; /* right */
1035 glTexCoord[2] = 0.0; /* top */
1036 glTexCoord[3] = (float) This->currentDesc.Height / (float) This->pow2Height; /* bottom */
1038 IWineD3DSurface_PreLoad(iface);
1040 ENTER_GL();
1042 /* Disable some fancy graphics effects */
1043 glDisable(GL_LIGHTING);
1044 checkGLcall("glDisable GL_LIGHTING");
1045 glDisable(GL_DEPTH_TEST);
1046 checkGLcall("glDisable GL_DEPTH_TEST");
1047 glDisable(GL_FOG);
1048 checkGLcall("glDisable GL_FOG");
1049 glDisable(GL_CULL_FACE);
1050 checkGLcall("glDisable GL_CULL_FACE");
1051 glDisable(GL_BLEND);
1052 checkGLcall("glDisable GL_BLEND");
1053 glDisable(GL_STENCIL_TEST);
1054 checkGLcall("glDisable GL_STENCIL_TEST");
1056 glEnable(GL_TEXTURE_2D);
1057 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1058 checkGLcall("glEnable glBindTexture");
1060 /* No filtering for blts */
1061 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1062 checkGLcall("glTexParameteri");
1063 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1064 checkGLcall("glTexParameteri");
1066 /* Start drawing a quad */
1067 glBegin(GL_QUADS);
1069 glColor3d(1.0f, 1.0f, 1.0f);
1070 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1071 glVertex3f(0, 0, 0.0);
1073 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1074 glVertex3f(0, This->currentDesc.Height, 0.0);
1076 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1077 glVertex3d(This->currentDesc.Width, This->currentDesc.Height, 0.0);
1079 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1080 glVertex3f(This->currentDesc.Width, 0, 0.0);
1082 glEnd();
1083 checkGLcall("glEnd");
1085 /* Unbind the texture */
1086 glBindTexture(GL_TEXTURE_2D, 0);
1087 checkGLcall("glEnable glBindTexture");
1089 LEAVE_GL();
1092 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1093 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1094 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1095 const char *buffername = "";
1096 IWineD3DSwapChainImpl *swapchain = NULL;
1097 BOOL backbuf = FALSE;
1099 if (!(This->Flags & SFLAG_LOCKED)) {
1100 WARN("trying to Unlock an unlocked surf@%p\n", This);
1101 return WINED3DERR_INVALIDCALL;
1104 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
1105 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1107 if(swapchain) {
1108 int i;
1109 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
1110 if(iface == swapchain->backBuffer[i]) {
1111 backbuf = TRUE;
1112 break;
1117 if (backbuf) {
1118 buffername = "backBuffer";
1119 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
1120 buffername = "frontBuffer";
1121 } else if (iface == myDevice->depthStencilBuffer) {
1122 buffername = "depthStencilBuffer";
1123 } else if (iface == myDevice->render_targets[0]) {
1124 buffername = "renderTarget";
1128 if (swapchain != NULL) {
1129 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1132 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
1134 if (!(This->Flags & SFLAG_DIRTY)) {
1135 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1136 goto unlock_end;
1139 if (0 == This->resource.usage) { /* classic surface */
1140 IWineD3DBaseTextureImpl *impl;
1141 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1142 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1143 * states need resetting
1145 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1146 if(impl->baseTexture.bindCount) {
1147 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1149 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1151 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
1153 /****************************
1154 * TODO: Render targets are 'special' and
1155 * ?some? locking needs to be passed onto the context manager
1156 * so that it becomes possible to use auxiliary buffers, pbuffers
1157 * render-to-texture, shared, cached contexts etc...
1158 * ****************************/
1159 IWineD3DSwapChainImpl *implSwapChain;
1160 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
1162 if ((backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->render_targets[0]) && wined3d_settings.rendertargetlock_mode != RTL_DISABLE) {
1163 int tex;
1165 ENTER_GL();
1167 /* glDrawPixels transforms the raster position as though it was a vertex -
1168 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1169 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1170 myDevice->last_was_rhw = TRUE;
1171 /* Apply the projection and world matrices, it sets up orthogonal projection due to last_was_rhw */
1172 StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock);
1173 StateTable[STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))].apply(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), myDevice->stateBlock);
1174 /* Will reapply the projection matrix too */
1175 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL);
1177 if (iface == implSwapChain->frontBuffer) {
1178 glDrawBuffer(GL_FRONT);
1179 checkGLcall("glDrawBuffer GL_FRONT");
1180 } else if (backbuf || iface == myDevice->render_targets[0]) {
1181 glDrawBuffer(GL_BACK);
1182 checkGLcall("glDrawBuffer GL_BACK");
1185 /* Disable higher textures before calling glDrawPixels */
1186 for(tex = 1; tex < GL_LIMITS(samplers); tex++) {
1187 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1188 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + tex));
1189 checkGLcall("glActiveTextureARB");
1191 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(tex));
1192 glDisable(GL_TEXTURE_2D);
1193 checkGLcall("glDisable GL_TEXTURE_2D");
1194 glDisable(GL_TEXTURE_1D);
1195 checkGLcall("glDisable GL_TEXTURE_1D");
1197 /* Activate texture 0, but don't disable it necessarily */
1198 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1199 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1200 checkGLcall("glActiveTextureARB");
1202 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
1204 /* And back buffers are not blended. Disable the depth test,
1205 that helps performance */
1206 glDisable(GL_BLEND);
1207 glDisable(GL_DEPTH_TEST);
1208 glDisable(GL_FOG);
1210 switch(wined3d_settings.rendertargetlock_mode) {
1211 case RTL_AUTO:
1212 case RTL_READDRAW:
1213 case RTL_TEXDRAW:
1214 flush_to_framebuffer_drawpixels(This);
1215 break;
1217 case RTL_READTEX:
1218 case RTL_TEXTEX:
1219 flush_to_framebuffer_texture(iface);
1220 break;
1222 case RTL_DISABLE:
1224 static BOOL warned = FALSE;
1225 if(!warned) {
1226 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1227 warned = TRUE;
1230 break;
1233 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1234 glDrawBuffer(GL_BACK);
1235 vcheckGLcall("glDrawBuffer");
1237 if(myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_TRUE ||
1238 myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_USEW) glEnable(GL_DEPTH_TEST);
1239 if (myDevice->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1240 if (myDevice->stateBlock->renderState[WINED3DRS_FOGENABLE]) glEnable(GL_FOG);
1242 LEAVE_GL();
1244 /** restore clean dirty state */
1245 IWineD3DSurface_CleanDirtyRect(iface);
1247 } else if(wined3d_settings.rendertargetlock_mode != RTL_DISABLE) {
1248 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1250 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1252 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1254 if (iface == myDevice->depthStencilBuffer) {
1255 FIXME("TODO stencil depth surface unlocking surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1256 } else {
1257 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1260 } else {
1261 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1264 unlock_end:
1265 This->Flags &= ~SFLAG_LOCKED;
1266 memset(&This->lockedRect, 0, sizeof(RECT));
1267 return WINED3D_OK;
1270 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1271 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1272 WINED3DLOCKED_RECT lock;
1273 UINT usage;
1274 BITMAPINFO* b_info;
1275 HDC ddc;
1276 DWORD *masks;
1277 HRESULT hr;
1278 RGBQUAD col[256];
1279 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1281 TRACE("(%p)->(%p)\n",This,pHDC);
1283 if(This->Flags & SFLAG_USERPTR) {
1284 ERR("Not supported on surfaces with an application-provided surfaces\n");
1285 return DDERR_NODC;
1288 /* Give more detailed info for ddraw */
1289 if (This->Flags & SFLAG_DCINUSE)
1290 return DDERR_DCALREADYCREATED;
1292 /* Can't GetDC if the surface is locked */
1293 if (This->Flags & SFLAG_LOCKED)
1294 return WINED3DERR_INVALIDCALL;
1296 memset(&lock, 0, sizeof(lock)); /* To be sure */
1298 /* Create a DIB section if there isn't a hdc yet */
1299 if(!This->hDC) {
1300 int extraline = 0;
1301 SYSTEM_INFO sysInfo;
1303 if(This->Flags & SFLAG_ACTIVELOCK) {
1304 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1307 switch (This->bytesPerPixel) {
1308 case 2:
1309 case 4:
1310 /* Allocate extra space to store the RGB bit masks. */
1311 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1312 break;
1314 case 3:
1315 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1316 break;
1318 default:
1319 /* Allocate extra space for a palette. */
1320 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1321 sizeof(BITMAPINFOHEADER)
1322 + sizeof(RGBQUAD)
1323 * (1 << (This->bytesPerPixel * 8)));
1324 break;
1327 if (!b_info)
1328 return E_OUTOFMEMORY;
1330 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1331 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1332 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1333 * add an extra line to the dib section
1335 GetSystemInfo(&sysInfo);
1336 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1337 extraline = 1;
1338 TRACE("Adding an extra line to the dib section\n");
1341 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1342 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1343 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1344 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1345 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1346 /* Use the full pow2 image size(assigned below) because LockRect
1347 * will need it for a full glGetTexImage call
1349 } else {
1350 b_info->bmiHeader.biWidth = This->pow2Width;
1351 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1352 b_info->bmiHeader.biSizeImage = This->resource.size + extraline * IWineD3DSurface_GetPitch(iface);
1354 b_info->bmiHeader.biPlanes = 1;
1355 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1357 b_info->bmiHeader.biXPelsPerMeter = 0;
1358 b_info->bmiHeader.biYPelsPerMeter = 0;
1359 b_info->bmiHeader.biClrUsed = 0;
1360 b_info->bmiHeader.biClrImportant = 0;
1362 /* Get the bit masks */
1363 masks = (DWORD *) &(b_info->bmiColors);
1364 switch (This->resource.format) {
1365 case WINED3DFMT_R8G8B8:
1366 usage = DIB_RGB_COLORS;
1367 b_info->bmiHeader.biCompression = BI_RGB;
1368 break;
1370 case WINED3DFMT_X1R5G5B5:
1371 case WINED3DFMT_A1R5G5B5:
1372 case WINED3DFMT_A4R4G4B4:
1373 case WINED3DFMT_X4R4G4B4:
1374 case WINED3DFMT_R3G3B2:
1375 case WINED3DFMT_A8R3G3B2:
1376 case WINED3DFMT_A2B10G10R10:
1377 case WINED3DFMT_A8B8G8R8:
1378 case WINED3DFMT_X8B8G8R8:
1379 case WINED3DFMT_A2R10G10B10:
1380 case WINED3DFMT_R5G6B5:
1381 case WINED3DFMT_A16B16G16R16:
1382 usage = 0;
1383 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1384 masks[0] = formatEntry->redMask;
1385 masks[1] = formatEntry->greenMask;
1386 masks[2] = formatEntry->blueMask;
1387 break;
1389 default:
1390 /* Don't know palette */
1391 b_info->bmiHeader.biCompression = BI_RGB;
1392 usage = 0;
1393 break;
1396 ddc = GetDC(0);
1397 if (ddc == 0) {
1398 HeapFree(GetProcessHeap(), 0, b_info);
1399 return HRESULT_FROM_WIN32(GetLastError());
1402 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);
1403 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1404 ReleaseDC(0, ddc);
1406 if (!This->dib.DIBsection) {
1407 ERR("CreateDIBSection failed!\n");
1408 HeapFree(GetProcessHeap(), 0, b_info);
1409 return HRESULT_FROM_WIN32(GetLastError());
1412 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1414 /* copy the existing surface to the dib section */
1415 if(This->resource.allocatedMemory) {
1416 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1417 /* We won't need that any more */
1418 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1419 } else {
1420 /* This is to make LockRect read the gl Texture although memory is allocated */
1421 This->Flags |= SFLAG_GLDIRTY;
1424 HeapFree(GetProcessHeap(), 0, b_info);
1426 /* Use the dib section from now on */
1427 This->resource.allocatedMemory = This->dib.bitmap_data;
1429 /* Now allocate a HDC */
1430 This->hDC = CreateCompatibleDC(0);
1431 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1432 TRACE("using wined3d palette %p\n", This->palette);
1433 SelectPalette(This->hDC,
1434 This->palette ? This->palette->hpal : 0,
1435 FALSE);
1437 This->Flags |= SFLAG_DIBSECTION;
1440 /* Lock the surface */
1441 hr = IWineD3DSurface_LockRect(iface,
1442 &lock,
1443 NULL,
1445 if(FAILED(hr)) {
1446 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1447 /* keep the dib section */
1448 return hr;
1451 if(This->resource.format == WINED3DFMT_P8 ||
1452 This->resource.format == WINED3DFMT_A8P8) {
1453 unsigned int n;
1454 if(This->palette) {
1455 PALETTEENTRY ent[256];
1457 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1458 for (n=0; n<256; n++) {
1459 col[n].rgbRed = ent[n].peRed;
1460 col[n].rgbGreen = ent[n].peGreen;
1461 col[n].rgbBlue = ent[n].peBlue;
1462 col[n].rgbReserved = 0;
1464 } else {
1465 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1467 for (n=0; n<256; n++) {
1468 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1469 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1470 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1471 col[n].rgbReserved = 0;
1475 SetDIBColorTable(This->hDC, 0, 256, col);
1478 *pHDC = This->hDC;
1479 TRACE("returning %p\n",*pHDC);
1480 This->Flags |= SFLAG_DCINUSE;
1482 return WINED3D_OK;
1485 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1486 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1488 TRACE("(%p)->(%p)\n",This,hDC);
1490 if (!(This->Flags & SFLAG_DCINUSE))
1491 return D3DERR_INVALIDCALL;
1493 /* we locked first, so unlock now */
1494 IWineD3DSurface_UnlockRect(iface);
1496 This->Flags &= ~SFLAG_DCINUSE;
1498 return WINED3D_OK;
1501 /* ******************************************************
1502 IWineD3DSurface Internal (No mapping to directx api) parts follow
1503 ****************************************************** */
1505 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) {
1506 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1507 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1509 /* Default values: From the surface */
1510 *format = formatEntry->glFormat;
1511 *internal = formatEntry->glInternal;
1512 *type = formatEntry->glType;
1513 *convert = NO_CONVERSION;
1514 *target_bpp = This->bytesPerPixel;
1516 /* Ok, now look if we have to do any conversion */
1517 switch(This->resource.format) {
1518 case WINED3DFMT_P8:
1519 /* ****************
1520 Paletted Texture
1521 **************** */
1522 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1523 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1525 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1526 *format = GL_RGBA;
1527 *internal = GL_RGBA;
1528 *type = GL_UNSIGNED_BYTE;
1529 *target_bpp = 4;
1530 if(colorkey_active) {
1531 *convert = CONVERT_PALETTED_CK;
1532 } else {
1533 *convert = CONVERT_PALETTED;
1537 break;
1539 case WINED3DFMT_R3G3B2:
1540 /* **********************
1541 GL_UNSIGNED_BYTE_3_3_2
1542 ********************** */
1543 if (colorkey_active) {
1544 /* This texture format will never be used.. So do not care about color keying
1545 up until the point in time it will be needed :-) */
1546 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1548 break;
1550 case WINED3DFMT_R5G6B5:
1551 if (colorkey_active) {
1552 *convert = CONVERT_CK_565;
1553 *format = GL_RGBA;
1554 *internal = GL_RGBA;
1555 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1557 break;
1559 case WINED3DFMT_R8G8B8:
1560 if (colorkey_active) {
1561 *convert = CONVERT_CK_RGB24;
1562 *format = GL_RGBA;
1563 *internal = GL_RGBA;
1564 *type = GL_UNSIGNED_INT_8_8_8_8;
1565 *target_bpp = 4;
1567 break;
1569 case WINED3DFMT_X8R8G8B8:
1570 if (colorkey_active) {
1571 *convert = CONVERT_RGB32_888;
1572 *format = GL_RGBA;
1573 *internal = GL_RGBA;
1574 *type = GL_UNSIGNED_INT_8_8_8_8;
1576 break;
1578 default:
1579 break;
1582 return WINED3D_OK;
1585 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1586 BYTE *source, *dest;
1587 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1589 switch (convert) {
1590 case NO_CONVERSION:
1592 memcpy(dst, src, pitch * height);
1593 break;
1595 case CONVERT_PALETTED:
1596 case CONVERT_PALETTED_CK:
1598 IWineD3DPaletteImpl* pal = surf->palette;
1599 BYTE table[256][4];
1600 unsigned int i;
1601 unsigned int x, y;
1603 if( pal == NULL) {
1604 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1607 if (pal == NULL) {
1608 /* Still no palette? Use the device's palette */
1609 /* Get the surface's palette */
1610 for (i = 0; i < 256; i++) {
1611 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1613 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1614 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1615 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1616 if ((convert == CONVERT_PALETTED_CK) &&
1617 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1618 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1619 /* We should maybe here put a more 'neutral' color than the standard bright purple
1620 one often used by application to prevent the nice purple borders when bi-linear
1621 filtering is on */
1622 table[i][3] = 0x00;
1623 } else {
1624 table[i][3] = 0xFF;
1627 } else {
1628 TRACE("Using surface palette %p\n", pal);
1629 /* Get the surface's palette */
1630 for (i = 0; i < 256; i++) {
1631 table[i][0] = pal->palents[i].peRed;
1632 table[i][1] = pal->palents[i].peGreen;
1633 table[i][2] = pal->palents[i].peBlue;
1634 if ((convert == CONVERT_PALETTED_CK) &&
1635 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1636 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1637 /* We should maybe here put a more 'neutral' color than the standard bright purple
1638 one often used by application to prevent the nice purple borders when bi-linear
1639 filtering is on */
1640 table[i][3] = 0x00;
1641 } else {
1642 table[i][3] = 0xFF;
1647 for (y = 0; y < height; y++)
1649 source = src + pitch * y;
1650 dest = dst + outpitch * y;
1651 /* This is an 1 bpp format, using the width here is fine */
1652 for (x = 0; x < width; x++) {
1653 BYTE color = *source++;
1654 *dest++ = table[color][0];
1655 *dest++ = table[color][1];
1656 *dest++ = table[color][2];
1657 *dest++ = table[color][3];
1661 break;
1663 case CONVERT_CK_565:
1665 /* Converting the 565 format in 5551 packed to emulate color-keying.
1667 Note : in all these conversion, it would be best to average the averaging
1668 pixels to get the color of the pixel that will be color-keyed to
1669 prevent 'color bleeding'. This will be done later on if ever it is
1670 too visible.
1672 Note2: Nvidia documents say that their driver does not support alpha + color keying
1673 on the same surface and disables color keying in such a case
1675 unsigned int x, y;
1676 WORD *Source;
1677 WORD *Dest;
1679 TRACE("Color keyed 565\n");
1681 for (y = 0; y < height; y++) {
1682 Source = (WORD *) (src + y * pitch);
1683 Dest = (WORD *) (dst + y * outpitch);
1684 for (x = 0; x < width; x++ ) {
1685 WORD color = *Source++;
1686 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1687 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1688 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1689 *Dest |= 0x0001;
1691 Dest++;
1695 break;
1697 default:
1698 ERR("Unsupported conversation type %d\n", convert);
1700 return WINED3D_OK;
1703 /* This function is used in case of 8bit paletted textures to upload the palette.
1704 For now it only supports GL_EXT_paletted_texture extension but support for other
1705 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1707 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1708 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1709 IWineD3DPaletteImpl* pal = This->palette;
1710 BYTE table[256][4];
1711 int i;
1713 if (pal == NULL) {
1714 /* Still no palette? Use the device's palette */
1715 /* Get the surface's palette */
1716 for (i = 0; i < 256; i++) {
1717 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1719 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1720 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1721 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1722 if ((convert == CONVERT_PALETTED_CK) &&
1723 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1724 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1725 /* We should maybe here put a more 'neutral' color than the standard bright purple
1726 one often used by application to prevent the nice purple borders when bi-linear
1727 filtering is on */
1728 table[i][3] = 0x00;
1729 } else {
1730 table[i][3] = 0xFF;
1733 } else {
1734 TRACE("Using surface palette %p\n", pal);
1735 /* Get the surface's palette */
1736 for (i = 0; i < 256; i++) {
1737 table[i][0] = pal->palents[i].peRed;
1738 table[i][1] = pal->palents[i].peGreen;
1739 table[i][2] = pal->palents[i].peBlue;
1740 if ((convert == CONVERT_PALETTED_CK) &&
1741 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1742 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1743 /* We should maybe here put a more 'neutral' color than the standard bright purple
1744 one often used by application to prevent the nice purple borders when bi-linear
1745 filtering is on */
1746 table[i][3] = 0x00;
1747 } else {
1748 table[i][3] = 0xFF;
1752 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1755 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1756 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1757 GLenum format, internal, type;
1758 CONVERT_TYPES convert;
1759 int bpp;
1760 int width, pitch, outpitch;
1761 BYTE *mem;
1763 if (This->Flags & SFLAG_INTEXTURE) {
1764 TRACE("Surface already in texture\n");
1765 return WINED3D_OK;
1767 if (This->Flags & SFLAG_DIRTY) {
1768 TRACE("Reloading because surface is dirty\n");
1769 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1770 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1771 /* Reload: vice versa OR */
1772 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1773 /* Also reload: Color key is active AND the color key has changed */
1774 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1775 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1776 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1777 TRACE("Reloading because of color keying\n");
1778 } else {
1779 TRACE("surface isn't dirty\n");
1780 return WINED3D_OK;
1783 This->Flags &= ~SFLAG_DIRTY;
1785 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1786 * These resources are not bound by device size or format restrictions. Because of this,
1787 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1788 * However, these resources can always be created, locked, and copied.
1790 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1792 FIXME("(%p) Operation not supported for scratch textures\n",This);
1793 return WINED3DERR_INVALIDCALL;
1796 if (This->Flags & SFLAG_INPBUFFER) {
1797 if (This->glDescription.level != 0)
1798 FIXME("Surface in texture is only supported for level 0\n");
1799 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1800 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1801 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1802 This->resource.format == WINED3DFMT_DXT5)
1803 FIXME("Format %d not supported\n", This->resource.format);
1804 else {
1805 GLint prevRead;
1807 ENTER_GL();
1809 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1810 vcheckGLcall("glGetIntegerv");
1811 glReadBuffer(GL_BACK);
1812 vcheckGLcall("glReadBuffer");
1814 glCopyTexImage2D(This->glDescription.target,
1815 This->glDescription.level,
1816 This->glDescription.glFormatInternal,
1819 This->currentDesc.Width,
1820 This->currentDesc.Height,
1823 checkGLcall("glCopyTexImage2D");
1824 glReadBuffer(prevRead);
1825 vcheckGLcall("glReadBuffer");
1827 LEAVE_GL();
1829 TRACE("Updating target %d\n", This->glDescription.target);
1830 This->Flags |= SFLAG_INTEXTURE;
1832 return WINED3D_OK;
1835 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1836 This->Flags |= SFLAG_GLCKEY;
1837 This->glCKey = This->SrcBltCKey;
1839 else This->Flags &= ~SFLAG_GLCKEY;
1841 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1843 /* The width is in 'length' not in bytes */
1844 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1845 width = This->currentDesc.Width;
1846 else
1847 width = This->pow2Width;
1849 pitch = IWineD3DSurface_GetPitch(iface);
1851 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1852 int height = This->glRect.bottom - This->glRect.top;
1854 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1855 outpitch = width * bpp;
1856 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1858 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1859 if(!mem) {
1860 ERR("Out of memory %d, %d!\n", outpitch, height);
1861 return WINED3DERR_OUTOFVIDEOMEMORY;
1863 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1865 This->Flags |= SFLAG_CONVERTED;
1866 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1867 d3dfmt_p8_upload_palette(iface, convert);
1868 This->Flags &= ~SFLAG_CONVERTED;
1869 mem = This->resource.allocatedMemory;
1870 } else {
1871 This->Flags &= ~SFLAG_CONVERTED;
1872 mem = This->resource.allocatedMemory;
1875 /* Make sure the correct pitch is used */
1876 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1878 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1879 TRACE("non power of two support\n");
1880 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1881 if (mem) {
1882 surface_upload_data(This, This->pow2Width, This->pow2Height, format, type, mem);
1884 } else {
1885 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1886 if (mem) {
1887 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1891 /* Restore the default pitch */
1892 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1894 if (mem != This->resource.allocatedMemory)
1895 HeapFree(GetProcessHeap(), 0, mem);
1897 #if 0
1899 static unsigned int gen = 0;
1900 char buffer[4096];
1901 ++gen;
1902 if ((gen % 10) == 0) {
1903 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1904 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1907 * debugging crash code
1908 if (gen == 250) {
1909 void** test = NULL;
1910 *test = 0;
1914 #endif
1916 if (!(This->Flags & SFLAG_DONOTFREE)) {
1917 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1918 This->resource.allocatedMemory = NULL;
1921 return WINED3D_OK;
1924 #include <errno.h>
1925 #include <stdio.h>
1926 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1927 FILE* f = NULL;
1928 UINT i, y;
1929 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1930 char *allocatedMemory;
1931 char *textureRow;
1932 IWineD3DSwapChain *swapChain = NULL;
1933 int width, height;
1934 GLuint tmpTexture = 0;
1935 DWORD color;
1936 /*FIXME:
1937 Textures my not be stored in ->allocatedgMemory and a GlTexture
1938 so we should lock the surface before saving a snapshot, or at least check that
1940 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1941 by calling GetTexImage and in compressed form by calling
1942 GetCompressedTexImageARB. Queried compressed images can be saved and
1943 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1944 texture images do not need to be processed by the GL and should
1945 significantly improve texture loading performance relative to uncompressed
1946 images. */
1948 /* Setup the width and height to be the internal texture width and height. */
1949 width = This->pow2Width;
1950 height = This->pow2Height;
1951 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1952 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1954 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1955 /* 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 */
1956 GLint prevRead;
1957 ENTER_GL();
1958 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1959 glEnable(GL_TEXTURE_2D);
1961 glGenTextures(1, &tmpTexture);
1962 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1964 glTexImage2D(GL_TEXTURE_2D,
1966 GL_RGBA,
1967 width,
1968 height,
1969 0/*border*/,
1970 GL_RGBA,
1971 GL_UNSIGNED_INT_8_8_8_8_REV,
1972 NULL);
1974 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1975 vcheckGLcall("glGetIntegerv");
1976 glReadBuffer(GL_BACK);
1977 vcheckGLcall("glReadBuffer");
1978 glCopyTexImage2D(GL_TEXTURE_2D,
1980 GL_RGBA,
1983 width,
1984 height,
1987 checkGLcall("glCopyTexImage2D");
1988 glReadBuffer(prevRead);
1989 LEAVE_GL();
1991 } else { /* bind the real texture */
1992 IWineD3DSurface_PreLoad(iface);
1994 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1995 ENTER_GL();
1996 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1997 glGetTexImage(GL_TEXTURE_2D,
1998 This->glDescription.level,
1999 GL_RGBA,
2000 GL_UNSIGNED_INT_8_8_8_8_REV,
2001 allocatedMemory);
2002 checkGLcall("glTexImage2D");
2003 if (tmpTexture) {
2004 glBindTexture(GL_TEXTURE_2D, 0);
2005 glDeleteTextures(1, &tmpTexture);
2007 LEAVE_GL();
2009 f = fopen(filename, "w+");
2010 if (NULL == f) {
2011 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2012 return WINED3DERR_INVALIDCALL;
2014 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
2015 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2016 /* TGA header */
2017 fputc(0,f);
2018 fputc(0,f);
2019 fputc(2,f);
2020 fputc(0,f);
2021 fputc(0,f);
2022 fputc(0,f);
2023 fputc(0,f);
2024 fputc(0,f);
2025 fputc(0,f);
2026 fputc(0,f);
2027 fputc(0,f);
2028 fputc(0,f);
2029 /* short width*/
2030 fwrite(&width,2,1,f);
2031 /* short height */
2032 fwrite(&height,2,1,f);
2033 /* format rgba */
2034 fputc(0x20,f);
2035 fputc(0x28,f);
2036 /* raw data */
2037 /* 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*/
2038 if(swapChain)
2039 textureRow = allocatedMemory + (width * (height - 1) *4);
2040 else
2041 textureRow = allocatedMemory;
2042 for (y = 0 ; y < height; y++) {
2043 for (i = 0; i < width; i++) {
2044 color = *((DWORD*)textureRow);
2045 fputc((color >> 16) & 0xFF, f); /* B */
2046 fputc((color >> 8) & 0xFF, f); /* G */
2047 fputc((color >> 0) & 0xFF, f); /* R */
2048 fputc((color >> 24) & 0xFF, f); /* A */
2049 textureRow += 4;
2051 /* take two rows of the pointer to the texture memory */
2052 if(swapChain)
2053 (textureRow-= width << 3);
2056 TRACE("Closing file\n");
2057 fclose(f);
2059 if(swapChain) {
2060 IWineD3DSwapChain_Release(swapChain);
2062 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2063 return WINED3D_OK;
2066 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2067 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2068 This->Flags &= ~SFLAG_DIRTY;
2069 This->dirtyRect.left = This->currentDesc.Width;
2070 This->dirtyRect.top = This->currentDesc.Height;
2071 This->dirtyRect.right = 0;
2072 This->dirtyRect.bottom = 0;
2073 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2074 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2075 return WINED3D_OK;
2079 * Slightly inefficient way to handle multiple dirty rects but it works :)
2081 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2082 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2083 IWineD3DBaseTexture *baseTexture = NULL;
2084 This->Flags |= SFLAG_DIRTY;
2085 if (NULL != pDirtyRect) {
2086 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2087 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2088 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2089 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2090 } else {
2091 This->dirtyRect.left = 0;
2092 This->dirtyRect.top = 0;
2093 This->dirtyRect.right = This->currentDesc.Width;
2094 This->dirtyRect.bottom = This->currentDesc.Height;
2096 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2097 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2098 /* if the container is a basetexture then mark it dirty. */
2099 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2100 TRACE("Passing to conatiner\n");
2101 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2102 IWineD3DBaseTexture_Release(baseTexture);
2104 return WINED3D_OK;
2107 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2108 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2110 TRACE("This %p, container %p\n", This, container);
2112 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2114 TRACE("Setting container to %p from %p\n", container, This->container);
2115 This->container = container;
2117 return WINED3D_OK;
2120 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2121 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2122 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2124 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2125 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2126 return WINED3DERR_INVALIDCALL;
2129 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2130 if (format == WINED3DFMT_UNKNOWN) {
2131 This->resource.size = 0;
2132 } else if (format == WINED3DFMT_DXT1) {
2133 /* DXT1 is half byte per pixel */
2134 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2136 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2137 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2138 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2139 } else {
2140 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2141 This->resource.size *= This->pow2Height;
2145 /* Setup some glformat defaults */
2146 This->glDescription.glFormat = formatEntry->glFormat;
2147 This->glDescription.glFormatInternal = formatEntry->glInternal;
2148 This->glDescription.glType = formatEntry->glType;
2150 if (format != WINED3DFMT_UNKNOWN) {
2151 This->bytesPerPixel = formatEntry->bpp;
2152 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2153 } else {
2154 This->bytesPerPixel = 0;
2155 This->pow2Size = 0;
2158 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2160 This->resource.format = format;
2162 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);
2164 return WINED3D_OK;
2167 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2168 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2170 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2171 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2172 ERR("Not supported on render targets\n");
2173 return WINED3DERR_INVALIDCALL;
2176 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2177 WARN("Surface is locked or the HDC is in use\n");
2178 return WINED3DERR_INVALIDCALL;
2181 if(Mem && Mem != This->resource.allocatedMemory) {
2183 /* Do I have to copy the old surface content? */
2184 if(This->Flags & SFLAG_DIBSECTION) {
2185 /* Release the DC. No need to hold the critical section for the update
2186 * Thread because this thread runs only on front buffers, but this method
2187 * fails for render targets in the check above.
2189 SelectObject(This->hDC, This->dib.holdbitmap);
2190 DeleteDC(This->hDC);
2191 /* Release the DIB section */
2192 DeleteObject(This->dib.DIBsection);
2193 This->dib.bitmap_data = NULL;
2194 This->resource.allocatedMemory = NULL;
2195 This->hDC = NULL;
2196 This->Flags &= ~SFLAG_DIBSECTION;
2197 } else if(!(This->Flags & SFLAG_USERPTR)) {
2198 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2200 This->resource.allocatedMemory = Mem;
2201 This->Flags |= SFLAG_USERPTR;
2202 } else if(This->Flags & SFLAG_USERPTR) {
2203 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2204 This->resource.allocatedMemory = NULL;
2205 This->Flags &= ~SFLAG_USERPTR;
2207 return WINED3D_OK;
2210 /* TODO: replace this function with context management routines */
2211 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2212 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2214 if(inPBuffer) {
2215 This->Flags |= SFLAG_INPBUFFER;
2216 } else {
2217 This->Flags &= ~SFLAG_INPBUFFER;
2220 if(inTexture) {
2221 This->Flags |= SFLAG_INTEXTURE;
2222 } else {
2223 This->Flags &= ~SFLAG_INTEXTURE;
2226 return WINED3D_OK;
2229 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2230 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2231 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2232 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2234 /* Flipping is only supported on RenderTargets */
2235 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2237 if(override) {
2238 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2239 * FIXME("(%p) Target override is not supported by now\n", This);
2240 * Additionally, it isn't really possible to support triple-buffering
2241 * properly on opengl at all
2245 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2246 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2249 /* Not called from the VTable */
2250 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2251 WINED3DRECT rect;
2252 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2253 IWineD3DSwapChainImpl *swapchain = NULL;
2254 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2255 BOOL SrcOK = TRUE;
2257 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2259 /* Get the swapchain. One of the surfaces has to be a primary surface */
2260 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2261 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2262 else if(Src) {
2263 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2264 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2265 else return WINED3DERR_INVALIDCALL;
2266 } else {
2267 swapchain = NULL;
2270 if (DestRect) {
2271 rect.x1 = DestRect->left;
2272 rect.y1 = DestRect->top;
2273 rect.x2 = DestRect->right;
2274 rect.y2 = DestRect->bottom;
2275 } else {
2276 rect.x1 = 0;
2277 rect.y1 = 0;
2278 rect.x2 = This->currentDesc.Width;
2279 rect.y2 = This->currentDesc.Height;
2282 /* Half-life does a Blt from the back buffer to the front buffer,
2283 * Full surface size, no flags... Use present instead
2285 if(Src)
2287 /* First, check if we can do a Flip */
2289 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2290 if( SrcRect ) {
2291 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2292 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2293 SrcOK = TRUE;
2295 } else {
2296 SrcOK = TRUE;
2299 /* Check the Destination rect and the surface sizes */
2300 if(SrcOK &&
2301 (rect.x1 == 0) && (rect.y1 == 0) &&
2302 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2303 (This->currentDesc.Width == Src->currentDesc.Width) &&
2304 (This->currentDesc.Height == Src->currentDesc.Height)) {
2305 /* These flags are unimportant for the flag check, remove them */
2307 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2308 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2310 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2312 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2313 * take very long, while a flip is fast.
2314 * This applies to Half-Life, which does such Blts every time it finished
2315 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2316 * menu. This is also used by all apps when they do windowed rendering
2318 * The problem is that flipping is not really the same as copying. After a
2319 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2320 * untouched. Therefore it's necessary to override the swap effect
2321 * and to set it back after the flip.
2324 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2326 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2327 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2328 NULL, NULL, 0, NULL);
2330 swapchain->presentParms.SwapEffect = orig_swap;
2332 return WINED3D_OK;
2337 /* Blt from texture to rendertarget? */
2338 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2339 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2341 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2342 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2343 float glTexCoord[4];
2344 DWORD oldCKey;
2345 DDCOLORKEY oldBltCKey = {0,0};
2346 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2347 GLint oldStencil, oldNVRegisterCombiners = 0;
2348 GLint alphafunc;
2349 GLclampf alpharef;
2350 RECT SourceRectangle;
2351 GLint oldDraw;
2353 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2355 if(SrcRect) {
2356 SourceRectangle.left = SrcRect->left;
2357 SourceRectangle.right = SrcRect->right;
2358 SourceRectangle.top = SrcRect->top;
2359 SourceRectangle.bottom = SrcRect->bottom;
2360 } else {
2361 SourceRectangle.left = 0;
2362 SourceRectangle.right = Src->currentDesc.Width;
2363 SourceRectangle.top = 0;
2364 SourceRectangle.bottom = Src->currentDesc.Height;
2367 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2368 /* Fall back to software */
2369 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2370 SourceRectangle.left, SourceRectangle.top,
2371 SourceRectangle.right, SourceRectangle.bottom);
2372 return WINED3DERR_INVALIDCALL;
2375 /* Color keying: Check if we have to do a color keyed blt,
2376 * and if not check if a color key is activated.
2378 oldCKey = Src->CKeyFlags;
2379 if(!(Flags & DDBLT_KEYSRC) &&
2380 Src->CKeyFlags & DDSD_CKSRCBLT) {
2381 /* Ok, the surface has a color key, but we shall not use it -
2382 * Deactivate it for now, LoadTexture will catch this
2384 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2387 /* Color keying */
2388 if(Flags & DDBLT_KEYDEST) {
2389 oldBltCKey = This->SrcBltCKey;
2390 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2391 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2393 This->SrcBltCKey = This->DestBltCKey;
2394 } else if (Flags & DDBLT_KEYSRC)
2395 oldBltCKey = This->SrcBltCKey;
2397 /* Now load the surface */
2398 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2400 ENTER_GL();
2402 /* Save all the old stuff until we have a proper opengl state manager */
2403 oldLight = glIsEnabled(GL_LIGHTING);
2404 oldFog = glIsEnabled(GL_FOG);
2405 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2406 oldBlend = glIsEnabled(GL_BLEND);
2407 oldCull = glIsEnabled(GL_CULL_FACE);
2408 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2409 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2411 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2412 oldNVRegisterCombiners = glIsEnabled(GL_REGISTER_COMBINERS_NV);
2415 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2416 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2417 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2418 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2420 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2421 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2422 TRACE("Drawing to front buffer\n");
2423 glDrawBuffer(GL_FRONT);
2424 checkGLcall("glDrawBuffer GL_FRONT");
2427 /* Unbind the old texture */
2428 glBindTexture(GL_TEXTURE_2D, 0);
2429 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
2431 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2432 /* We use texture unit 0 for blts */
2433 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2434 checkGLcall("glActiveTextureARB");
2435 } else {
2436 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2439 /* Disable some fancy graphics effects */
2440 glDisable(GL_LIGHTING);
2441 checkGLcall("glDisable GL_LIGHTING");
2442 glDisable(GL_DEPTH_TEST);
2443 checkGLcall("glDisable GL_DEPTH_TEST");
2444 glDisable(GL_FOG);
2445 checkGLcall("glDisable GL_FOG");
2446 glDisable(GL_BLEND);
2447 checkGLcall("glDisable GL_BLEND");
2448 glDisable(GL_CULL_FACE);
2449 checkGLcall("glDisable GL_CULL_FACE");
2450 glDisable(GL_STENCIL_TEST);
2451 checkGLcall("glDisable GL_STENCIL_TEST");
2452 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2453 glDisable(GL_REGISTER_COMBINERS_NV);
2454 checkGLcall("glDisable GL_REGISTER_COMBINERS_NV");
2457 /* Ok, we need 2d textures, but not 1D or 3D */
2458 glDisable(GL_TEXTURE_1D);
2459 checkGLcall("glDisable GL_TEXTURE_1D");
2460 glEnable(GL_TEXTURE_2D);
2461 checkGLcall("glEnable GL_TEXTURE_2D");
2462 glDisable(GL_TEXTURE_3D);
2463 checkGLcall("glDisable GL_TEXTURE_3D");
2465 /* Bind the texture */
2466 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2467 checkGLcall("glBindTexture");
2469 glEnable(GL_SCISSOR_TEST);
2471 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2473 /* No filtering for blts */
2474 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2475 GL_NEAREST);
2476 checkGLcall("glTexParameteri");
2477 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2478 GL_NEAREST);
2479 checkGLcall("glTexParameteri");
2480 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2481 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2482 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2483 checkGLcall("glTexEnvi");
2485 /* This is for color keying */
2486 if(Flags & DDBLT_KEYSRC) {
2487 glEnable(GL_ALPHA_TEST);
2488 checkGLcall("glEnable GL_ALPHA_TEST");
2489 glAlphaFunc(GL_NOTEQUAL, 0.0);
2490 checkGLcall("glAlphaFunc\n");
2491 } else {
2492 glDisable(GL_ALPHA_TEST);
2493 checkGLcall("glDisable GL_ALPHA_TEST");
2496 /* Draw a textured quad
2498 myDevice->last_was_rhw = TRUE;
2499 /* Apply the projection matrix, it sets up orthogonal projection due to last_was_rhw */
2500 StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock);
2501 StateTable[STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))].apply(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), myDevice->stateBlock);
2502 /* That will reapply the projection matrix too */
2503 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL);
2505 glBegin(GL_QUADS);
2507 glColor3d(1.0f, 1.0f, 1.0f);
2508 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2509 glVertex3f(rect.x1,
2510 rect.y1,
2511 0.0);
2513 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2514 glVertex3f(rect.x1, rect.y2, 0.0);
2516 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2517 glVertex3f(rect.x2,
2518 rect.y2,
2519 0.0);
2521 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2522 glVertex3f(rect.x2,
2523 rect.y1,
2524 0.0);
2525 glEnd();
2526 checkGLcall("glEnd");
2528 /* Unbind the texture */
2529 glBindTexture(GL_TEXTURE_2D, 0);
2530 checkGLcall("glEnable glBindTexture");
2532 /* Restore the old settings */
2533 if(oldLight) {
2534 glEnable(GL_LIGHTING);
2535 checkGLcall("glEnable GL_LIGHTING");
2537 if(oldFog) {
2538 glEnable(GL_FOG);
2539 checkGLcall("glEnable GL_FOG");
2541 if(oldDepth) {
2542 glEnable(GL_DEPTH_TEST);
2543 checkGLcall("glEnable GL_DEPTH_TEST");
2545 if(oldBlend) {
2546 glEnable(GL_BLEND);
2547 checkGLcall("glEnable GL_BLEND");
2549 if(oldCull) {
2550 glEnable(GL_CULL_FACE);
2551 checkGLcall("glEnable GL_CULL_FACE");
2553 if(oldStencil) {
2554 glEnable(GL_STENCIL_TEST);
2555 checkGLcall("glEnable GL_STENCIL_TEST");
2557 if(!oldAlpha) {
2558 glDisable(GL_ALPHA_TEST);
2559 checkGLcall("glDisable GL_ALPHA_TEST");
2560 } else {
2561 glEnable(GL_ALPHA_TEST);
2562 checkGLcall("glEnable GL_ALPHA_TEST");
2564 if (GL_SUPPORT(NV_REGISTER_COMBINERS) && oldNVRegisterCombiners) {
2565 glEnable(GL_REGISTER_COMBINERS_NV);
2566 checkGLcall("glEnable GL_REGISTER_COMBINERS_NV");
2569 glAlphaFunc(alphafunc, alpharef);
2570 checkGLcall("glAlphaFunc\n");
2572 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2573 glDrawBuffer(oldDraw);
2576 /* Restore the color key flags */
2577 if(oldCKey != Src->CKeyFlags) {
2578 Src->CKeyFlags = oldCKey;
2581 /* Restore the old color key */
2582 if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
2583 This->SrcBltCKey = oldBltCKey;
2585 LEAVE_GL();
2587 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2588 This->Flags |= SFLAG_GLDIRTY;
2590 return WINED3D_OK;
2594 /* Blt from rendertarget to texture? */
2595 if( (SrcSurface == swapchain->frontBuffer) ||
2596 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2597 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2598 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2599 UINT row;
2600 WINED3DRECT srect;
2601 float xrel, yrel;
2603 TRACE("Blt from rendertarget to texture\n");
2605 /* Call preload for the surface to make sure it isn't dirty */
2606 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2608 if(SrcRect) {
2609 srect.x1 = SrcRect->left;
2610 srect.y1 = SrcRect->top;
2611 srect.x2 = SrcRect->right;
2612 srect.y2 = SrcRect->bottom;
2613 } else {
2614 srect.x1 = 0;
2615 srect.y1 = 0;
2616 srect.x2 = Src->currentDesc.Width;
2617 srect.y2 = Src->currentDesc.Height;
2620 ENTER_GL();
2622 /* Bind the target texture */
2623 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2624 checkGLcall("glBindTexture");
2625 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2626 glReadBuffer(GL_BACK);
2627 } else {
2628 glReadBuffer(GL_FRONT);
2630 checkGLcall("glReadBuffer");
2632 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2633 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2635 /* I have to process this row by row to swap the image,
2636 * otherwise it would be upside down, so streching in y direction
2637 * doesn't cost extra time
2639 * However, streching in x direction can be avoided if not necessary
2641 for(row = rect.y1; row < rect.y2; row++) {
2642 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2643 /* Well, that stuff works, but it's very slow.
2644 * find a better way instead
2646 UINT col;
2647 for(col = rect.x1; col < rect.x2; col++) {
2648 glCopyTexSubImage2D(GL_TEXTURE_2D,
2649 0, /* level */
2650 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2651 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2652 1, 1);
2654 } else {
2655 glCopyTexSubImage2D(GL_TEXTURE_2D,
2656 0, /* level */
2657 rect.x1, rect.y2 + rect.y1 - row - 1, /* xoffset, yoffset */
2658 srect.x1, row - rect.y1,
2659 rect.x2-rect.x1, 1);
2663 vcheckGLcall("glCopyTexSubImage2D");
2664 LEAVE_GL();
2666 if(!(This->Flags & SFLAG_DONOTFREE)) {
2667 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2668 This->resource.allocatedMemory = NULL;
2669 } else {
2670 This->Flags |= SFLAG_GLDIRTY;
2673 return WINED3D_OK;
2678 if (Flags & DDBLT_COLORFILL) {
2679 /* This is easy to handle for the D3D Device... */
2680 DWORD color;
2681 IWineD3DSwapChainImpl *implSwapChain;
2683 TRACE("Colorfill\n");
2685 /* The color as given in the Blt function is in the format of the frame-buffer...
2686 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2688 if (This->resource.format == WINED3DFMT_P8) {
2689 if (This->palette) {
2690 color = ((0xFF000000) |
2691 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2692 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2693 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2694 } else {
2695 color = 0xFF000000;
2698 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2699 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2700 color = 0xFFFFFFFF;
2701 } else {
2702 color = ((0xFF000000) |
2703 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2704 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2705 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2708 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2709 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2710 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2712 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2713 color = DDBltFx->u5.dwFillColor;
2715 else {
2716 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2717 return WINED3DERR_INVALIDCALL;
2720 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2721 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2722 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2723 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2724 glDrawBuffer(GL_BACK);
2725 checkGLcall("glDrawBuffer(GL_BACK)");
2727 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2728 glDrawBuffer(GL_FRONT);
2729 checkGLcall("glDrawBuffer(GL_FRONT)");
2731 else {
2732 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2733 return WINED3DERR_INVALIDCALL;
2736 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2738 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2739 1 /* Number of rectangles */,
2740 &rect,
2741 WINED3DCLEAR_TARGET,
2742 color,
2743 0.0 /* Z */,
2744 0 /* Stencil */);
2746 /* Restore the original draw buffer */
2747 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2748 glDrawBuffer(GL_BACK);
2749 vcheckGLcall("glDrawBuffer");
2752 return WINED3D_OK;
2755 /* Default: Fall back to the generic blt */
2756 return WINED3DERR_INVALIDCALL;
2759 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2760 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2761 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2762 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2763 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2765 /* Special cases for RenderTargets */
2766 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2767 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2768 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2771 /* For the rest call the X11 surface implementation.
2772 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2773 * other Blts are rather rare
2775 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2778 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2779 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2780 TRACE("(%p)->(%x)\n", This, Flags);
2782 switch (Flags)
2784 case DDGBS_CANBLT:
2785 case DDGBS_ISBLTDONE:
2786 return DD_OK;
2788 default:
2789 return DDERR_INVALIDPARAMS;
2793 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2794 /* XXX: DDERR_INVALIDSURFACETYPE */
2796 TRACE("(%p)->(%08x)\n",iface,Flags);
2797 switch (Flags) {
2798 case DDGFS_CANFLIP:
2799 case DDGFS_ISFLIPDONE:
2800 return DD_OK;
2802 default:
2803 return DDERR_INVALIDPARAMS;
2807 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2808 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2809 TRACE("(%p)\n", This);
2811 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2814 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2815 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2816 TRACE("(%p)\n", This);
2818 /* So far we don't lose anything :) */
2819 This->Flags &= ~SFLAG_LOST;
2820 return WINED3D_OK;
2823 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2824 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2825 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2826 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2828 /* Special cases for RenderTargets */
2829 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2830 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2832 RECT SrcRect, DstRect;
2833 DWORD Flags=0;
2835 if(rsrc) {
2836 SrcRect.left = rsrc->left;
2837 SrcRect.top= rsrc->top;
2838 SrcRect.bottom = rsrc->bottom;
2839 SrcRect.right = rsrc->right;
2840 } else {
2841 SrcRect.left = 0;
2842 SrcRect.top = 0;
2843 SrcRect.right = srcImpl->currentDesc.Width;
2844 SrcRect.bottom = srcImpl->currentDesc.Height;
2847 DstRect.left = dstx;
2848 DstRect.top=dsty;
2849 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2850 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2852 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2853 if(trans & DDBLTFAST_SRCCOLORKEY)
2854 Flags |= DDBLT_KEYSRC;
2855 if(trans & DDBLTFAST_DESTCOLORKEY)
2856 Flags |= DDBLT_KEYDEST;
2857 if(trans & DDBLTFAST_WAIT)
2858 Flags |= DDBLT_WAIT;
2859 if(trans & DDBLTFAST_DONOTWAIT)
2860 Flags |= DDBLT_DONOTWAIT;
2862 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2866 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2869 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2870 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2871 TRACE("(%p)->(%p)\n", This, Pal);
2873 *Pal = (IWineD3DPalette *) This->palette;
2874 return DD_OK;
2877 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2878 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2879 RGBQUAD col[256];
2880 IWineD3DPaletteImpl *pal = This->palette;
2881 unsigned int n;
2882 TRACE("(%p)\n", This);
2884 if(This->resource.format == WINED3DFMT_P8 ||
2885 This->resource.format == WINED3DFMT_A8P8)
2887 TRACE("Dirtifying surface\n");
2888 This->Flags |= SFLAG_DIRTY;
2891 if(This->Flags & SFLAG_DIBSECTION) {
2892 TRACE("(%p): Updating the hdc's palette\n", This);
2893 for (n=0; n<256; n++) {
2894 if(pal) {
2895 col[n].rgbRed = pal->palents[n].peRed;
2896 col[n].rgbGreen = pal->palents[n].peGreen;
2897 col[n].rgbBlue = pal->palents[n].peBlue;
2898 } else {
2899 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2900 /* Use the default device palette */
2901 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2902 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2903 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2905 col[n].rgbReserved = 0;
2907 SetDIBColorTable(This->hDC, 0, 256, col);
2910 return WINED3D_OK;
2913 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2914 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2915 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2916 TRACE("(%p)->(%p)\n", This, Pal);
2918 if(This->palette != NULL)
2919 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2920 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2922 if(PalImpl != NULL) {
2923 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2924 /* Set the device's main palette if the palette
2925 * wasn't a primary palette before
2927 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2928 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2929 unsigned int i;
2931 for(i=0; i < 256; i++) {
2932 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2936 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2939 This->palette = PalImpl;
2941 return IWineD3DSurface_RealizePalette(iface);
2944 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2945 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2946 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
2948 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2949 FIXME(" colorkey value not supported (%08x) !\n", Flags);
2950 return DDERR_INVALIDPARAMS;
2953 /* Dirtify the surface, but only if a key was changed */
2954 if(CKey) {
2955 switch (Flags & ~DDCKEY_COLORSPACE) {
2956 case DDCKEY_DESTBLT:
2957 This->DestBltCKey = *CKey;
2958 This->CKeyFlags |= DDSD_CKDESTBLT;
2959 break;
2961 case DDCKEY_DESTOVERLAY:
2962 This->DestOverlayCKey = *CKey;
2963 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2964 break;
2966 case DDCKEY_SRCOVERLAY:
2967 This->SrcOverlayCKey = *CKey;
2968 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2969 break;
2971 case DDCKEY_SRCBLT:
2972 This->SrcBltCKey = *CKey;
2973 This->CKeyFlags |= DDSD_CKSRCBLT;
2974 break;
2977 else {
2978 switch (Flags & ~DDCKEY_COLORSPACE) {
2979 case DDCKEY_DESTBLT:
2980 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2981 break;
2983 case DDCKEY_DESTOVERLAY:
2984 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2985 break;
2987 case DDCKEY_SRCOVERLAY:
2988 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2989 break;
2991 case DDCKEY_SRCBLT:
2992 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2993 break;
2997 return WINED3D_OK;
3000 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3001 /** Check against the maximum texture sizes supported by the video card **/
3002 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3004 TRACE("%p\n", This);
3005 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3006 /* one of three options
3007 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)
3008 2: Set the texture to the maxium size (bad idea)
3009 3: WARN and return WINED3DERR_NOTAVAILABLE;
3010 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.
3012 WARN("(%p) Creating an oversized surface\n", This);
3013 This->Flags |= SFLAG_OVERSIZE;
3015 /* This will be initialized on the first blt */
3016 This->glRect.left = 0;
3017 This->glRect.top = 0;
3018 This->glRect.right = 0;
3019 This->glRect.bottom = 0;
3020 } else {
3021 /* No oversize, gl rect is the full texture size */
3022 This->Flags &= ~SFLAG_OVERSIZE;
3023 This->glRect.left = 0;
3024 This->glRect.top = 0;
3025 This->glRect.right = This->pow2Width;
3026 This->glRect.bottom = This->pow2Height;
3029 return WINED3D_OK;
3032 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3033 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3034 DWORD ret;
3035 TRACE("(%p)\n", This);
3037 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3038 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3039 ie pitch = (width/4) * bytes per block */
3040 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3041 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3042 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3043 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3044 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3045 else {
3046 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3047 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3048 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3049 } else {
3050 ret = This->bytesPerPixel * This->pow2Width;
3052 /* Surfaces are 32 bit aligned */
3053 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3055 TRACE("(%p) Returning %d\n", This, ret);
3056 return ret;
3059 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3060 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3062 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3064 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3066 TRACE("(%p): Not an overlay surface\n", This);
3067 return DDERR_NOTAOVERLAYSURFACE;
3070 return WINED3D_OK;
3073 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3074 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3076 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3078 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3080 TRACE("(%p): Not an overlay surface\n", This);
3081 return DDERR_NOTAOVERLAYSURFACE;
3084 return WINED3D_OK;
3087 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3088 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3089 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3091 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3093 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3095 TRACE("(%p): Not an overlay surface\n", This);
3096 return DDERR_NOTAOVERLAYSURFACE;
3099 return WINED3D_OK;
3102 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3103 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3104 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3105 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3107 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3109 TRACE("(%p): Not an overlay surface\n", This);
3110 return DDERR_NOTAOVERLAYSURFACE;
3113 return WINED3D_OK;
3116 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3118 /* IUnknown */
3119 IWineD3DSurfaceImpl_QueryInterface,
3120 IWineD3DSurfaceImpl_AddRef,
3121 IWineD3DSurfaceImpl_Release,
3122 /* IWineD3DResource */
3123 IWineD3DSurfaceImpl_GetParent,
3124 IWineD3DSurfaceImpl_GetDevice,
3125 IWineD3DSurfaceImpl_SetPrivateData,
3126 IWineD3DSurfaceImpl_GetPrivateData,
3127 IWineD3DSurfaceImpl_FreePrivateData,
3128 IWineD3DSurfaceImpl_SetPriority,
3129 IWineD3DSurfaceImpl_GetPriority,
3130 IWineD3DSurfaceImpl_PreLoad,
3131 IWineD3DSurfaceImpl_GetType,
3132 /* IWineD3DSurface */
3133 IWineD3DSurfaceImpl_GetContainer,
3134 IWineD3DSurfaceImpl_GetDesc,
3135 IWineD3DSurfaceImpl_LockRect,
3136 IWineD3DSurfaceImpl_UnlockRect,
3137 IWineD3DSurfaceImpl_GetDC,
3138 IWineD3DSurfaceImpl_ReleaseDC,
3139 IWineD3DSurfaceImpl_Flip,
3140 IWineD3DSurfaceImpl_Blt,
3141 IWineD3DSurfaceImpl_GetBltStatus,
3142 IWineD3DSurfaceImpl_GetFlipStatus,
3143 IWineD3DSurfaceImpl_IsLost,
3144 IWineD3DSurfaceImpl_Restore,
3145 IWineD3DSurfaceImpl_BltFast,
3146 IWineD3DSurfaceImpl_GetPalette,
3147 IWineD3DSurfaceImpl_SetPalette,
3148 IWineD3DSurfaceImpl_RealizePalette,
3149 IWineD3DSurfaceImpl_SetColorKey,
3150 IWineD3DSurfaceImpl_GetPitch,
3151 IWineD3DSurfaceImpl_SetMem,
3152 IWineD3DSurfaceImpl_SetOverlayPosition,
3153 IWineD3DSurfaceImpl_GetOverlayPosition,
3154 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3155 IWineD3DSurfaceImpl_UpdateOverlay,
3156 /* Internal use: */
3157 IWineD3DSurfaceImpl_CleanDirtyRect,
3158 IWineD3DSurfaceImpl_AddDirtyRect,
3159 IWineD3DSurfaceImpl_LoadTexture,
3160 IWineD3DSurfaceImpl_SaveSnapshot,
3161 IWineD3DSurfaceImpl_SetContainer,
3162 IWineD3DSurfaceImpl_SetPBufferState,
3163 IWineD3DSurfaceImpl_SetGlTextureDesc,
3164 IWineD3DSurfaceImpl_GetGlDesc,
3165 IWineD3DSurfaceImpl_GetData,
3166 IWineD3DSurfaceImpl_SetFormat,
3167 IWineD3DSurfaceImpl_PrivateSetup