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
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
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);
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);
64 GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory));
65 checkGLcall("glGetCompressedTexImageARB()");
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);
75 glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
76 This->glDescription.glType, This->resource.allocatedMemory);
77 checkGLcall("glGetTexImage()");
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.
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
98 * -----------------------------------
101 * we're repacking the data to the expected texture width
103 * |<-texture width ->| -->pow2width| /\
104 * |111111111111111111222222222222222| |
105 * |222333333333333333333444444444444| texture height
109 * | empty | pow2height
111 * -----------------------------------
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;
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");
155 TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data);
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");
163 TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This, width, height, data);
165 glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data);
166 checkGLcall("glTexSubImage2D");
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);
177 glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, NULL);
178 checkGLcall("glTexImage2D");
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 ERR("Probably FIXME: Calling query interface with NULL riid\n");
194 if (IsEqualGUID(riid, &IID_IUnknown)
195 || IsEqualGUID(riid, &IID_IWineD3DBase)
196 || IsEqualGUID(riid, &IID_IWineD3DResource)
197 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
198 IUnknown_AddRef((IUnknown*)iface);
203 return E_NOINTERFACE;
206 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
207 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
208 ULONG ref = InterlockedIncrement(&This->resource.ref);
209 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
213 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
214 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
215 ULONG ref = InterlockedDecrement(&This->resource.ref);
216 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
218 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
219 TRACE("(%p) : cleaning up\n", This);
220 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
222 TRACE("Deleting texture %d\n", This->glDescription.textureName);
223 glDeleteTextures(1, &This->glDescription.textureName);
227 if(This->Flags & SFLAG_DIBSECTION) {
229 SelectObject(This->hDC, This->dib.holdbitmap);
231 /* Release the DIB section */
232 DeleteObject(This->dib.DIBsection);
233 This->dib.bitmap_data = NULL;
234 This->resource.allocatedMemory = NULL;
236 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
238 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
239 if(iface == device->ddraw_primary)
240 device->ddraw_primary = NULL;
242 TRACE("(%p) Released\n", This);
243 HeapFree(GetProcessHeap(), 0, This);
249 /* ****************************************************
250 IWineD3DSurface IWineD3DResource parts follow
251 **************************************************** */
252 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
253 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
256 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
257 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
260 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
261 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
264 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
265 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
268 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
269 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
272 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
273 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
276 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
277 /* TODO: re-write the way textures and managed,
278 * use a 'opengl context manager' to manage RenderTarget surfaces
279 ** *********************************************************/
281 /* TODO: check for locks */
282 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
283 IWineD3DBaseTexture *baseTexture = NULL;
284 TRACE("(%p)Checking to see if the container is a base texture\n", This);
285 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
286 TRACE("Passing to conatiner\n");
287 IWineD3DBaseTexture_PreLoad(baseTexture);
288 IWineD3DBaseTexture_Release(baseTexture);
290 TRACE("(%p) : About to load surface\n", This);
292 #if 0 /* TODO: context manager support */
293 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
295 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
296 if (!This->glDescription.level) {
297 if (!This->glDescription.textureName) {
298 glGenTextures(1, &This->glDescription.textureName);
299 checkGLcall("glGenTextures");
300 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
302 glBindTexture(This->glDescription.target, This->glDescription.textureName);
303 checkGLcall("glBindTexture");
304 IWineD3DSurface_LoadTexture(iface);
305 /* This is where we should be reducing the amount of GLMemoryUsed */
306 } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
307 /* assume this is a coding error not a real error for now */
308 FIXME("Mipmap surface has a glTexture bound to it!\n");
310 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
311 /* Tell opengl to try and keep this texture in video ram (well mostly) */
314 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
316 /* TODO: disable texture support, if it wastn't enabled when we entered. */
317 #if 0 /* TODO: context manager support */
318 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
319 /* we don't care when the state is disabled(if atall) */);
326 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
327 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
328 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
331 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
332 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
333 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
336 /* ******************************************************
337 IWineD3DSurface IWineD3DSurface parts follow
338 ****************************************************** */
340 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
341 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
342 IWineD3DBase *container = 0;
344 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
347 ERR("Called without a valid ppContainer.\n");
351 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
352 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
353 * GetContainer will return the Direct3D device used to create the surface.
355 if (This->container) {
356 container = This->container;
358 container = (IWineD3DBase *)This->resource.wineD3DDevice;
361 TRACE("Relaying to QueryInterface\n");
362 return IUnknown_QueryInterface(container, riid, ppContainer);
365 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
366 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
368 TRACE("(%p) : copying into %p\n", This, pDesc);
369 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
370 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
371 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
372 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
373 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
374 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
375 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
376 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
377 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
381 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
382 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
383 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
384 if (This->glDescription.textureName == 0 && textureName != 0) {
385 This->Flags |= SFLAG_DIRTY;
386 IWineD3DSurface_AddDirtyRect(iface, NULL);
388 This->glDescription.textureName = textureName;
389 This->glDescription.target = target;
392 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
393 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
394 TRACE("(%p) : returning %p\n", This, &This->glDescription);
395 *glDescription = &This->glDescription;
398 /* TODO: think about moving this down to resource? */
399 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
400 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
401 /* 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 */
402 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
403 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
405 return (CONST void*)(This->resource.allocatedMemory);
408 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
414 switch(This->resource.format)
418 /* GL can't return palettized data, so read ARGB pixels into a
419 * separate block of memory and convert them into palettized format
420 * in software. Slow, but if the app means to use palettized render
421 * targets and locks it...
423 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
424 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
425 * for the color channels when palettizing the colors.
428 type = GL_UNSIGNED_BYTE;
430 mem = HeapAlloc(GetProcessHeap(), 0, (rect->bottom - rect->top) * pitch);
432 ERR("Out of memory\n");
440 fmt = This->glDescription.glFormat;
441 type = This->glDescription.glType;
444 if (rect->left == 0 &&
445 rect->right == This->currentDesc.Width ) {
446 BYTE *row, *top, *bottom;
449 glReadPixels(0, rect->top,
450 This->currentDesc.Width,
451 rect->bottom - rect->top,
456 /* glReadPixels returns the image upside down, and there is no way to prevent this.
457 Flip the lines in software */
458 row = HeapAlloc(GetProcessHeap(), 0, pitch);
460 ERR("Out of memory\n");
464 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
465 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
466 memcpy(row, top, pitch);
467 memcpy(top, bottom, pitch);
468 memcpy(bottom, row, pitch);
472 HeapFree(GetProcessHeap(), 0, row);
474 if(This->lockedRect.top == 0 && This->lockedRect.bottom == This->currentDesc.Height) {
475 This->Flags &= ~SFLAG_GLDIRTY;
478 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
479 glReadPixels(rect->left,
480 rect->bottom - j - 1,
481 rect->right - rect->left,
485 (char *)mem + (pitch * (j-rect->top)));
489 vcheckGLcall("glReadPixels");
491 if(This->resource.format == WINED3DFMT_P8) {
493 DWORD width = pitch / 3;
496 pal = This->palette->palents;
498 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
501 for(y = rect->top; y < rect->bottom; y++) {
502 for(x = rect->left; x < rect->right; x++) {
503 /* start lines pixels */
504 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
505 BYTE *green = blue + 1;
506 BYTE *red = green + 1;
508 for(c = 0; c < 256; c++) {
509 if(*red == pal[c].peRed &&
510 *green == pal[c].peGreen &&
511 *blue == pal[c].peBlue)
513 *((BYTE *) dest + y * width + x) = c;
519 HeapFree(GetProcessHeap(), 0, mem);
523 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
524 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
525 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
526 IWineD3DSwapChainImpl *swapchain = NULL;
527 static UINT messages = 0; /* holds flags to disable fixme messages */
528 BOOL backbuf = FALSE;
530 /* fixme: should we really lock as such? */
531 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
532 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
533 FIXME("Warning: Surface is in texture memory or pbuffer\n");
534 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
537 if (!(This->Flags & SFLAG_LOCKABLE)) {
538 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
539 texture regions, and since the destination is an unlockable region we need
541 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
542 /*return WINED3DERR_INVALIDCALL; */
545 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
546 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
548 if (swapchain != NULL || iface == myDevice->render_targets[0] || iface == myDevice->depthStencilBuffer) {
549 if(swapchain != NULL) {
551 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
552 if(iface == swapchain->backBuffer[i]) {
559 TRACE("(%p, backBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
560 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
561 TRACE("(%p, frontBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
562 } else if (iface == myDevice->render_targets[0]) {
563 TRACE("(%p, renderTarget) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
564 } else if (iface == myDevice->depthStencilBuffer) {
565 TRACE("(%p, stencilBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
568 if (NULL != swapchain) {
569 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
574 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
577 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
580 pLockedRect->pBits = This->resource.allocatedMemory;
581 This->lockedRect.left = 0;
582 This->lockedRect.top = 0;
583 This->lockedRect.right = This->currentDesc.Width;
584 This->lockedRect.bottom = This->currentDesc.Height;
585 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);
587 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
589 if ((pRect->top < 0) ||
591 (pRect->left >= pRect->right) ||
592 (pRect->top >= pRect->bottom) ||
593 (pRect->right > This->currentDesc.Width) ||
594 (pRect->bottom > This->currentDesc.Height))
596 WARN(" Invalid values in pRect !!!\n");
597 return D3DERR_INVALIDCALL;
600 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
601 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
603 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
605 This->lockedRect.left = pRect->left;
606 This->lockedRect.top = pRect->top;
607 This->lockedRect.right = pRect->right;
608 This->lockedRect.bottom = pRect->bottom;
611 if (This->Flags & SFLAG_NONPOW2) {
612 TRACE("Locking non-power 2 texture\n");
615 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
616 /* classic surface TODO: non 2d surfaces?
617 These resources may be POOL_SYSTEMMEM, so they must not access the device */
618 TRACE("locking an ordinarary surface\n");
619 /* Check to see if memory has already been allocated from the surface*/
620 if ((NULL == This->resource.allocatedMemory) ||
621 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
622 /* Non-system memory surfaces */
624 This->Flags &= ~SFLAG_GLDIRTY;
626 /*Surface has no memory currently allocated to it!*/
627 TRACE("(%p) Locking rect\n" , This);
628 if(!This->resource.allocatedMemory) {
629 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
631 if (0 != This->glDescription.textureName) {
632 /* Now I have to copy thing bits back */
633 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
634 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
636 /* Make sure that the texture is loaded */
637 IWineD3DSurface_PreLoad(iface); /* Make sure there is a texture to bind! */
639 surface_download_data(This);
641 } else { /* Nothing to do */
642 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
646 pLockedRect->pBits = This->resource.allocatedMemory;
648 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
649 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
651 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
655 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
656 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
659 BOOL notInContext = FALSE;
660 IWineD3DSwapChainImpl *targetSwapChain = NULL;
666 * for render->surface copy begin to begin of allocatedMemory
667 * unlock can be more easy
670 TRACE("locking a render target\n");
672 if (This->resource.allocatedMemory == NULL)
673 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
675 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
676 pLockedRect->pBits = This->resource.allocatedMemory;
679 vcheckGLcall("glFlush");
680 glGetIntegerv(GL_READ_BUFFER, &prev_read);
681 vcheckGLcall("glIntegerv");
682 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
683 vcheckGLcall("glIntegerv");
685 /* Here's what we have to do:
686 See if the swapchain has the same context as the renderTarget or the surface is the render target.
687 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
688 and use the front back buffer as required.
689 if not, we need to switch contexts and then switchback at the end.
691 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
692 IWineD3DSurface_GetContainer(myDevice->render_targets[0], &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
694 /* 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! */
695 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->render_targets[0]) {
696 if (swapchain && iface == swapchain->frontBuffer) {
697 TRACE("locking front\n");
698 glReadBuffer(GL_FRONT);
700 else if (iface == myDevice->render_targets[0] || backbuf) {
701 TRACE("locking back buffer\n");
702 glReadBuffer(GL_BACK);
703 } else if (iface == myDevice->depthStencilBuffer) {
704 FIXME("Stencil Buffer lock unsupported for now\n");
706 FIXME("(%p) Shouldn't have got here!\n", This);
707 glReadBuffer(GL_BACK);
709 } else if (swapchain != NULL) {
710 IWineD3DSwapChainImpl *implSwapChain;
711 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
712 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
713 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
715 glReadBuffer(GL_BACK);
716 } else if (iface == swapchain->frontBuffer) {
717 glReadBuffer(GL_FRONT);
718 } else if (iface == myDevice->depthStencilBuffer) {
719 FIXME("Stencil Buffer lock unsupported for now\n");
721 FIXME("Should have got here!\n");
722 glReadBuffer(GL_BACK);
725 /* We need to switch contexts to be able to read the buffer!!! */
726 FIXME("The buffer requested isn't in the current openGL context\n");
728 /* TODO: check the contexts, to see if were shared with the current context */
730 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
732 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
733 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
735 /** the depth stencil in openGL has a format of GL_FLOAT
736 * which should be good for WINED3DFMT_D16_LOCKABLE
738 * it is unclear what format the stencil buffer is in except.
739 * 'Each index is converted to fixed point...
740 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
741 * mappings in the table GL_PIXEL_MAP_S_TO_S.
742 * glReadPixels(This->lockedRect.left,
743 * This->lockedRect.bottom - j - 1,
744 * This->lockedRect.right - This->lockedRect.left,
746 * GL_DEPTH_COMPONENT,
748 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
749 *****************************************/
750 if (!notInContext) { /* Only read the buffer if it's in the current context */
751 switch(wined3d_settings.rendertargetlock_mode) {
755 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
760 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
761 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
766 static BOOL warned = FALSE;
768 ERR("Application tries to lock the render target, but render target locking is disabled\n");
775 TRACE("Resetting buffer\n");
777 glReadBuffer(prev_read);
778 vcheckGLcall("glReadBuffer");
782 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
785 FIXME("TODO stencil depth surface locking surf%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
788 glReadPixels(This->lockedRect.left,
789 This->lockedRect.bottom - j - 1,
790 This->lockedRect.right - This->lockedRect.left,
792 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
799 FIXME("unsupported locking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
802 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
805 IWineD3DBaseTexture *pBaseTexture;
808 * as seen in msdn docs
810 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
812 /** Dirtify Container if needed */
813 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
814 TRACE("Making container dirty\n");
815 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
816 IWineD3DBaseTexture_Release(pBaseTexture);
818 TRACE("Surface is standalone, no need to dirty the container\n");
822 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
824 This->Flags |= SFLAG_LOCKED;
828 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
830 GLint prev_rasterpos[4];
832 BOOL storechanged = FALSE;
836 glDisable(GL_TEXTURE_2D);
837 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
838 glDisable(GL_TEXTURE_1D);
839 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
842 vcheckGLcall("glFlush");
843 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
844 vcheckGLcall("glIntegerv");
845 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
846 vcheckGLcall("glIntegerv");
847 glPixelZoom(1.0, -1.0);
848 vcheckGLcall("glPixelZoom");
850 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
851 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
852 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
854 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
855 vcheckGLcall("glRasterPos2f");
857 /* Some drivers(radeon dri, others?) don't like exceptions during
858 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
859 * after ReleaseDC. Reading it will cause an exception, which x11drv will
860 * catch to put the dib section in InSync mode, which leads to a crash
861 * and a blocked x server on my radeon card.
863 * The following lines read the dib section so it is put in inSync mode
864 * before glDrawPixels is called and the crash is prevented. There won't
865 * be any interfering gdi accesses, because UnlockRect is called from
866 * ReleaseDC, and the app won't use the dc any more afterwards.
868 if(This->Flags & SFLAG_DIBSECTION) {
870 read = This->resource.allocatedMemory[0];
873 switch (This->resource.format) {
874 /* No special care needed */
875 case WINED3DFMT_A4R4G4B4:
876 case WINED3DFMT_R5G6B5:
877 case WINED3DFMT_A1R5G5B5:
878 case WINED3DFMT_R8G8B8:
879 type = This->glDescription.glType;
880 fmt = This->glDescription.glFormat;
881 mem = This->resource.allocatedMemory;
884 case WINED3DFMT_X4R4G4B4:
887 unsigned short *data;
888 data = (unsigned short *)This->resource.allocatedMemory;
889 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
895 type = This->glDescription.glType;
896 fmt = This->glDescription.glFormat;
897 mem = This->resource.allocatedMemory;
901 case WINED3DFMT_X1R5G5B5:
904 unsigned short *data;
905 data = (unsigned short *)This->resource.allocatedMemory;
906 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
912 type = This->glDescription.glType;
913 fmt = This->glDescription.glFormat;
914 mem = This->resource.allocatedMemory;
918 case WINED3DFMT_X8R8G8B8:
920 /* make sure the X byte is set to alpha on, since it
921 could be any random value. This fixes the intro movie in Pirates! */
924 data = (unsigned int *)This->resource.allocatedMemory;
925 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
934 case WINED3DFMT_A8R8G8B8:
936 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
937 vcheckGLcall("glPixelStorei");
939 type = This->glDescription.glType;
940 fmt = This->glDescription.glFormat;
941 mem = This->resource.allocatedMemory;
945 case WINED3DFMT_A2R10G10B10:
947 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
948 vcheckGLcall("glPixelStorei");
950 type = This->glDescription.glType;
951 fmt = This->glDescription.glFormat;
952 mem = This->resource.allocatedMemory;
958 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
959 int height = This->glRect.bottom - This->glRect.top;
960 type = GL_UNSIGNED_BYTE;
963 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
965 ERR("Out of memory\n");
968 d3dfmt_convert_surface(This->resource.allocatedMemory,
980 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
983 type = This->glDescription.glType;
984 fmt = This->glDescription.glFormat;
985 mem = This->resource.allocatedMemory;
988 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
989 (This->lockedRect.bottom - This->lockedRect.top)-1,
992 checkGLcall("glDrawPixels");
993 glPixelZoom(1.0,1.0);
994 vcheckGLcall("glPixelZoom");
996 glRasterPos3iv(&prev_rasterpos[0]);
997 vcheckGLcall("glRasterPos3iv");
999 /* Reset to previous pack row length */
1000 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1001 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1003 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
1004 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1007 if(mem != This->resource.allocatedMemory) HeapFree(GetProcessHeap(), 0, mem);
1011 static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
1012 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1013 float glTexCoord[4];
1015 glTexCoord[0] = 0.0; /* left */
1016 glTexCoord[1] = (float) This->currentDesc.Width / (float) This->pow2Width; /* right */
1017 glTexCoord[2] = 0.0; /* top */
1018 glTexCoord[3] = (float) This->currentDesc.Height / (float) This->pow2Height; /* bottom */
1020 IWineD3DSurface_PreLoad(iface);
1024 /* Disable some fancy graphics effects */
1025 glDisable(GL_LIGHTING);
1026 checkGLcall("glDisable GL_LIGHTING");
1027 glDisable(GL_DEPTH_TEST);
1028 checkGLcall("glDisable GL_DEPTH_TEST");
1030 checkGLcall("glDisable GL_FOG");
1031 glDisable(GL_CULL_FACE);
1032 checkGLcall("glDisable GL_CULL_FACE");
1033 glDisable(GL_BLEND);
1034 checkGLcall("glDisable GL_BLEND");
1035 glDisable(GL_STENCIL_TEST);
1036 checkGLcall("glDisable GL_STENCIL_TEST");
1038 glEnable(GL_TEXTURE_2D);
1039 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1040 checkGLcall("glEnable glBindTexture");
1042 /* No filtering for blts */
1043 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1044 checkGLcall("glTexParameteri");
1045 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1046 checkGLcall("glTexParameteri");
1048 /* Start drawing a quad */
1051 glColor3d(1.0f, 1.0f, 1.0f);
1052 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1053 glVertex3f(0, 0, 0.0);
1055 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1056 glVertex3f(0, This->currentDesc.Height, 0.0);
1058 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1059 glVertex3d(This->currentDesc.Width, This->currentDesc.Height, 0.0);
1061 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1062 glVertex3f(This->currentDesc.Width, 0, 0.0);
1065 checkGLcall("glEnd");
1067 /* Unbind the texture */
1068 glBindTexture(GL_TEXTURE_2D, 0);
1069 checkGLcall("glEnable glBindTexture");
1074 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1075 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1076 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1077 const char *buffername = "";
1078 IWineD3DSwapChainImpl *swapchain = NULL;
1079 BOOL backbuf = FALSE;
1081 if (!(This->Flags & SFLAG_LOCKED)) {
1082 WARN("trying to Unlock an unlocked surf@%p\n", This);
1083 return WINED3DERR_INVALIDCALL;
1086 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
1087 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1091 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
1092 if(iface == swapchain->backBuffer[i]) {
1100 buffername = "backBuffer";
1101 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
1102 buffername = "frontBuffer";
1103 } else if (iface == myDevice->depthStencilBuffer) {
1104 buffername = "depthStencilBuffer";
1105 } else if (iface == myDevice->render_targets[0]) {
1106 buffername = "renderTarget";
1110 if (swapchain != NULL) {
1111 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1114 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
1116 if (!(This->Flags & SFLAG_DIRTY)) {
1117 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1121 if (0 == This->resource.usage) { /* classic surface */
1122 IWineD3DBaseTextureImpl *impl;
1123 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1124 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1125 * states need resetting
1127 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1128 if(impl->baseTexture.bindCount) {
1129 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1131 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1133 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
1135 /****************************
1136 * TODO: Render targets are 'special' and
1137 * ?some? locking needs to be passed onto the context manager
1138 * so that it becomes possible to use auxiliary buffers, pbuffers
1139 * render-to-texture, shared, cached contexts etc...
1140 * ****************************/
1141 IWineD3DSwapChainImpl *implSwapChain;
1142 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
1144 if ((backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->render_targets[0]) && wined3d_settings.rendertargetlock_mode != RTL_DISABLE) {
1149 /* glDrawPixels transforms the raster position as though it was a vertex -
1150 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1151 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1152 d3ddevice_set_ortho(This->resource.wineD3DDevice);
1154 if (iface == implSwapChain->frontBuffer) {
1155 glDrawBuffer(GL_FRONT);
1156 checkGLcall("glDrawBuffer GL_FRONT");
1157 } else if (backbuf || iface == myDevice->render_targets[0]) {
1158 glDrawBuffer(GL_BACK);
1159 checkGLcall("glDrawBuffer GL_BACK");
1162 /* Disable higher textures before calling glDrawPixels */
1163 for(tex = 1; tex < GL_LIMITS(samplers); tex++) {
1164 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1165 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + tex));
1166 checkGLcall("glActiveTextureARB");
1168 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(tex));
1169 glDisable(GL_TEXTURE_2D);
1170 checkGLcall("glDisable GL_TEXTURE_2D");
1171 glDisable(GL_TEXTURE_1D);
1172 checkGLcall("glDisable GL_TEXTURE_1D");
1174 /* Activate texture 0, but don't disable it necessarily */
1175 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1176 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1177 checkGLcall("glActiveTextureARB");
1179 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
1181 /* And back buffers are not blended. Disable the depth test,
1182 that helps performance */
1183 glDisable(GL_BLEND);
1184 glDisable(GL_DEPTH_TEST);
1187 switch(wined3d_settings.rendertargetlock_mode) {
1191 flush_to_framebuffer_drawpixels(This);
1196 flush_to_framebuffer_texture(iface);
1201 static BOOL warned = FALSE;
1203 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1210 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1211 glDrawBuffer(GL_BACK);
1212 vcheckGLcall("glDrawBuffer");
1214 if(myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_TRUE ||
1215 myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_USEW) glEnable(GL_DEPTH_TEST);
1216 if (myDevice->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1217 if (myDevice->stateBlock->renderState[WINED3DRS_FOGENABLE]) glEnable(GL_FOG);
1221 /** restore clean dirty state */
1222 IWineD3DSurface_CleanDirtyRect(iface);
1224 } else if(wined3d_settings.rendertargetlock_mode != RTL_DISABLE) {
1225 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1227 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1229 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1231 if (iface == myDevice->depthStencilBuffer) {
1232 FIXME("TODO stencil depth surface unlocking surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1234 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1238 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1242 This->Flags &= ~SFLAG_LOCKED;
1243 memset(&This->lockedRect, 0, sizeof(RECT));
1247 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1248 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1249 WINED3DLOCKED_RECT lock;
1256 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1258 TRACE("(%p)->(%p)\n",This,pHDC);
1260 if(This->Flags & SFLAG_USERPTR) {
1261 ERR("Not supported on surfaces with an application-provided surfaces\n");
1265 /* Give more detailed info for ddraw */
1266 if (This->Flags & SFLAG_DCINUSE)
1267 return DDERR_DCALREADYCREATED;
1269 /* Can't GetDC if the surface is locked */
1270 if (This->Flags & SFLAG_LOCKED)
1271 return WINED3DERR_INVALIDCALL;
1273 memset(&lock, 0, sizeof(lock)); /* To be sure */
1275 /* Create a DIB section if there isn't a hdc yet */
1278 SYSTEM_INFO sysInfo;
1280 if(This->Flags & SFLAG_ACTIVELOCK) {
1281 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1284 switch (This->bytesPerPixel) {
1287 /* Allocate extra space to store the RGB bit masks. */
1288 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1292 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1296 /* Allocate extra space for a palette. */
1297 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1298 sizeof(BITMAPINFOHEADER)
1300 * (1 << (This->bytesPerPixel * 8)));
1305 return E_OUTOFMEMORY;
1307 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1308 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1309 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1310 * add an extra line to the dib section
1312 GetSystemInfo(&sysInfo);
1313 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1315 TRACE("Adding an extra line to the dib section\n");
1318 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1319 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1320 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1321 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1322 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1323 /* Use the full pow2 image size(assigned below) because LockRect
1324 * will need it for a full glGetTexImage call
1327 b_info->bmiHeader.biWidth = This->pow2Width;
1328 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1329 b_info->bmiHeader.biSizeImage = This->resource.size + extraline * IWineD3DSurface_GetPitch(iface);
1331 b_info->bmiHeader.biPlanes = 1;
1332 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1334 b_info->bmiHeader.biXPelsPerMeter = 0;
1335 b_info->bmiHeader.biYPelsPerMeter = 0;
1336 b_info->bmiHeader.biClrUsed = 0;
1337 b_info->bmiHeader.biClrImportant = 0;
1339 /* Get the bit masks */
1340 masks = (DWORD *) &(b_info->bmiColors);
1341 switch (This->resource.format) {
1342 case WINED3DFMT_R8G8B8:
1343 usage = DIB_RGB_COLORS;
1344 b_info->bmiHeader.biCompression = BI_RGB;
1347 case WINED3DFMT_X1R5G5B5:
1348 case WINED3DFMT_A1R5G5B5:
1349 case WINED3DFMT_A4R4G4B4:
1350 case WINED3DFMT_X4R4G4B4:
1351 case WINED3DFMT_R3G3B2:
1352 case WINED3DFMT_A8R3G3B2:
1353 case WINED3DFMT_A2B10G10R10:
1354 case WINED3DFMT_A8B8G8R8:
1355 case WINED3DFMT_X8B8G8R8:
1356 case WINED3DFMT_A2R10G10B10:
1357 case WINED3DFMT_R5G6B5:
1358 case WINED3DFMT_A16B16G16R16:
1360 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1361 masks[0] = formatEntry->redMask;
1362 masks[1] = formatEntry->greenMask;
1363 masks[2] = formatEntry->blueMask;
1367 /* Don't know palette */
1368 b_info->bmiHeader.biCompression = BI_RGB;
1375 HeapFree(GetProcessHeap(), 0, b_info);
1376 return HRESULT_FROM_WIN32(GetLastError());
1379 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);
1380 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1383 if (!This->dib.DIBsection) {
1384 ERR("CreateDIBSection failed!\n");
1385 HeapFree(GetProcessHeap(), 0, b_info);
1386 return HRESULT_FROM_WIN32(GetLastError());
1389 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1391 /* copy the existing surface to the dib section */
1392 if(This->resource.allocatedMemory) {
1393 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1394 /* We won't need that any more */
1395 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1397 /* This is to make LockRect read the gl Texture although memory is allocated */
1398 This->Flags |= SFLAG_GLDIRTY;
1401 HeapFree(GetProcessHeap(), 0, b_info);
1403 /* Use the dib section from now on */
1404 This->resource.allocatedMemory = This->dib.bitmap_data;
1406 /* Now allocate a HDC */
1407 This->hDC = CreateCompatibleDC(0);
1408 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1409 TRACE("using wined3d palette %p\n", This->palette);
1410 SelectPalette(This->hDC,
1411 This->palette ? This->palette->hpal : 0,
1414 This->Flags |= SFLAG_DIBSECTION;
1417 /* Lock the surface */
1418 hr = IWineD3DSurface_LockRect(iface,
1423 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1424 /* keep the dib section */
1428 if(This->resource.format == WINED3DFMT_P8 ||
1429 This->resource.format == WINED3DFMT_A8P8) {
1432 PALETTEENTRY ent[256];
1434 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1435 for (n=0; n<256; n++) {
1436 col[n].rgbRed = ent[n].peRed;
1437 col[n].rgbGreen = ent[n].peGreen;
1438 col[n].rgbBlue = ent[n].peBlue;
1439 col[n].rgbReserved = 0;
1442 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1444 for (n=0; n<256; n++) {
1445 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1446 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1447 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1448 col[n].rgbReserved = 0;
1452 SetDIBColorTable(This->hDC, 0, 256, col);
1456 TRACE("returning %p\n",*pHDC);
1457 This->Flags |= SFLAG_DCINUSE;
1462 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1463 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1465 TRACE("(%p)->(%p)\n",This,hDC);
1467 if (!(This->Flags & SFLAG_DCINUSE))
1468 return D3DERR_INVALIDCALL;
1470 /* we locked first, so unlock now */
1471 IWineD3DSurface_UnlockRect(iface);
1473 This->Flags &= ~SFLAG_DCINUSE;
1478 /* ******************************************************
1479 IWineD3DSurface Internal (No mapping to directx api) parts follow
1480 ****************************************************** */
1482 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) {
1483 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1484 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1486 /* Default values: From the surface */
1487 *format = formatEntry->glFormat;
1488 *internal = formatEntry->glInternal;
1489 *type = formatEntry->glType;
1490 *convert = NO_CONVERSION;
1491 *target_bpp = This->bytesPerPixel;
1493 /* Ok, now look if we have to do any conversion */
1494 switch(This->resource.format) {
1499 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1500 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1502 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1504 *internal = GL_RGBA;
1505 *type = GL_UNSIGNED_BYTE;
1507 if(colorkey_active) {
1508 *convert = CONVERT_PALETTED_CK;
1510 *convert = CONVERT_PALETTED;
1516 case WINED3DFMT_R3G3B2:
1517 /* **********************
1518 GL_UNSIGNED_BYTE_3_3_2
1519 ********************** */
1520 if (colorkey_active) {
1521 /* This texture format will never be used.. So do not care about color keying
1522 up until the point in time it will be needed :-) */
1523 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1527 case WINED3DFMT_R5G6B5:
1528 if (colorkey_active) {
1529 *convert = CONVERT_CK_565;
1531 *internal = GL_RGBA;
1532 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1536 case WINED3DFMT_R8G8B8:
1537 if (colorkey_active) {
1538 *convert = CONVERT_CK_RGB24;
1540 *internal = GL_RGBA;
1541 *type = GL_UNSIGNED_INT_8_8_8_8;
1546 case WINED3DFMT_X8R8G8B8:
1547 if (colorkey_active) {
1548 *convert = CONVERT_RGB32_888;
1550 *internal = GL_RGBA;
1551 *type = GL_UNSIGNED_INT_8_8_8_8;
1562 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1563 BYTE *source, *dest;
1564 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1569 memcpy(dst, src, pitch * height);
1572 case CONVERT_PALETTED:
1573 case CONVERT_PALETTED_CK:
1575 IWineD3DPaletteImpl* pal = surf->palette;
1581 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1585 /* Still no palette? Use the device's palette */
1586 /* Get the surface's palette */
1587 for (i = 0; i < 256; i++) {
1588 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1590 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1591 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1592 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1593 if ((convert == CONVERT_PALETTED_CK) &&
1594 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1595 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1596 /* We should maybe here put a more 'neutral' color than the standard bright purple
1597 one often used by application to prevent the nice purple borders when bi-linear
1605 TRACE("Using surface palette %p\n", pal);
1606 /* Get the surface's palette */
1607 for (i = 0; i < 256; i++) {
1608 table[i][0] = pal->palents[i].peRed;
1609 table[i][1] = pal->palents[i].peGreen;
1610 table[i][2] = pal->palents[i].peBlue;
1611 if ((convert == CONVERT_PALETTED_CK) &&
1612 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1613 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1614 /* We should maybe here put a more 'neutral' color than the standard bright purple
1615 one often used by application to prevent the nice purple borders when bi-linear
1624 for (y = 0; y < height; y++)
1626 source = src + pitch * y;
1627 dest = dst + outpitch * y;
1628 /* This is an 1 bpp format, using the width here is fine */
1629 for (x = 0; x < width; x++) {
1630 BYTE color = *source++;
1631 *dest++ = table[color][0];
1632 *dest++ = table[color][1];
1633 *dest++ = table[color][2];
1634 *dest++ = table[color][3];
1640 case CONVERT_CK_565:
1642 /* Converting the 565 format in 5551 packed to emulate color-keying.
1644 Note : in all these conversion, it would be best to average the averaging
1645 pixels to get the color of the pixel that will be color-keyed to
1646 prevent 'color bleeding'. This will be done later on if ever it is
1649 Note2: Nvidia documents say that their driver does not support alpha + color keying
1650 on the same surface and disables color keying in such a case
1656 TRACE("Color keyed 565\n");
1658 for (y = 0; y < height; y++) {
1659 Source = (WORD *) (src + y * pitch);
1660 Dest = (WORD *) (dst + y * outpitch);
1661 for (x = 0; x < width; x++ ) {
1662 WORD color = *Source++;
1663 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1664 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1665 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1675 ERR("Unsupported conversation type %d\n", convert);
1680 /* This function is used in case of 8bit paletted textures to upload the palette.
1681 For now it only supports GL_EXT_paletted_texture extension but support for other
1682 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1684 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1685 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1686 IWineD3DPaletteImpl* pal = This->palette;
1691 /* Still no palette? Use the device's palette */
1692 /* Get the surface's palette */
1693 for (i = 0; i < 256; i++) {
1694 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1696 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1697 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1698 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1699 if ((convert == CONVERT_PALETTED_CK) &&
1700 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1701 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1702 /* We should maybe here put a more 'neutral' color than the standard bright purple
1703 one often used by application to prevent the nice purple borders when bi-linear
1711 TRACE("Using surface palette %p\n", pal);
1712 /* Get the surface's palette */
1713 for (i = 0; i < 256; i++) {
1714 table[i][0] = pal->palents[i].peRed;
1715 table[i][1] = pal->palents[i].peGreen;
1716 table[i][2] = pal->palents[i].peBlue;
1717 if ((convert == CONVERT_PALETTED_CK) &&
1718 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1719 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1720 /* We should maybe here put a more 'neutral' color than the standard bright purple
1721 one often used by application to prevent the nice purple borders when bi-linear
1729 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1732 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1733 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1734 GLenum format, internal, type;
1735 CONVERT_TYPES convert;
1737 int width, pitch, outpitch;
1740 if (This->Flags & SFLAG_INTEXTURE) {
1741 TRACE("Surface already in texture\n");
1744 if (This->Flags & SFLAG_DIRTY) {
1745 TRACE("Reloading because surface is dirty\n");
1746 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1747 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1748 /* Reload: vice versa OR */
1749 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1750 /* Also reload: Color key is active AND the color key has changed */
1751 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1752 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1753 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1754 TRACE("Reloading because of color keying\n");
1756 TRACE("surface isn't dirty\n");
1760 This->Flags &= ~SFLAG_DIRTY;
1762 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1763 * These resources are not bound by device size or format restrictions. Because of this,
1764 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1765 * However, these resources can always be created, locked, and copied.
1767 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1769 FIXME("(%p) Operation not supported for scratch textures\n",This);
1770 return WINED3DERR_INVALIDCALL;
1773 if (This->Flags & SFLAG_INPBUFFER) {
1774 if (This->glDescription.level != 0)
1775 FIXME("Surface in texture is only supported for level 0\n");
1776 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1777 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1778 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1779 This->resource.format == WINED3DFMT_DXT5)
1780 FIXME("Format %d not supported\n", This->resource.format);
1786 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1787 vcheckGLcall("glGetIntegerv");
1788 glReadBuffer(GL_BACK);
1789 vcheckGLcall("glReadBuffer");
1791 glCopyTexImage2D(This->glDescription.target,
1792 This->glDescription.level,
1793 This->glDescription.glFormatInternal,
1796 This->currentDesc.Width,
1797 This->currentDesc.Height,
1800 checkGLcall("glCopyTexImage2D");
1801 glReadBuffer(prevRead);
1802 vcheckGLcall("glReadBuffer");
1806 TRACE("Updating target %d\n", This->glDescription.target);
1807 This->Flags |= SFLAG_INTEXTURE;
1812 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1813 This->Flags |= SFLAG_GLCKEY;
1814 This->glCKey = This->SrcBltCKey;
1816 else This->Flags &= ~SFLAG_GLCKEY;
1818 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1820 /* The width is in 'length' not in bytes */
1821 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1822 width = This->currentDesc.Width;
1824 width = This->pow2Width;
1826 pitch = IWineD3DSurface_GetPitch(iface);
1828 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1829 int height = This->glRect.bottom - This->glRect.top;
1831 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1832 outpitch = width * bpp;
1833 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1835 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1837 ERR("Out of memory %d, %d!\n", outpitch, height);
1838 return WINED3DERR_OUTOFVIDEOMEMORY;
1840 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1842 This->Flags |= SFLAG_CONVERTED;
1843 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1844 d3dfmt_p8_upload_palette(iface, convert);
1845 This->Flags &= ~SFLAG_CONVERTED;
1846 mem = This->resource.allocatedMemory;
1848 This->Flags &= ~SFLAG_CONVERTED;
1849 mem = This->resource.allocatedMemory;
1852 /* Make sure the correct pitch is used */
1853 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1855 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1856 TRACE("non power of two support\n");
1857 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1859 surface_upload_data(This, This->pow2Width, This->pow2Height, format, type, mem);
1862 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1864 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1868 /* Restore the default pitch */
1869 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1871 if (mem != This->resource.allocatedMemory)
1872 HeapFree(GetProcessHeap(), 0, mem);
1876 static unsigned int gen = 0;
1879 if ((gen % 10) == 0) {
1880 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1881 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1884 * debugging crash code
1893 if (!(This->Flags & SFLAG_DONOTFREE)) {
1894 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1895 This->resource.allocatedMemory = NULL;
1903 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1906 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1907 char *allocatedMemory;
1909 IWineD3DSwapChain *swapChain = NULL;
1911 GLuint tmpTexture = 0;
1914 Textures my not be stored in ->allocatedgMemory and a GlTexture
1915 so we should lock the surface before saving a snapshot, or at least check that
1917 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1918 by calling GetTexImage and in compressed form by calling
1919 GetCompressedTexImageARB. Queried compressed images can be saved and
1920 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1921 texture images do not need to be processed by the GL and should
1922 significantly improve texture loading performance relative to uncompressed
1925 /* Setup the width and height to be the internal texture width and height. */
1926 width = This->pow2Width;
1927 height = This->pow2Height;
1928 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1929 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1931 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1932 /* 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 */
1935 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1936 glEnable(GL_TEXTURE_2D);
1938 glGenTextures(1, &tmpTexture);
1939 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1941 glTexImage2D(GL_TEXTURE_2D,
1948 GL_UNSIGNED_INT_8_8_8_8_REV,
1951 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1952 vcheckGLcall("glGetIntegerv");
1953 glReadBuffer(GL_BACK);
1954 vcheckGLcall("glReadBuffer");
1955 glCopyTexImage2D(GL_TEXTURE_2D,
1964 checkGLcall("glCopyTexImage2D");
1965 glReadBuffer(prevRead);
1968 } else { /* bind the real texture */
1969 IWineD3DSurface_PreLoad(iface);
1971 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1973 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1974 glGetTexImage(GL_TEXTURE_2D,
1975 This->glDescription.level,
1977 GL_UNSIGNED_INT_8_8_8_8_REV,
1979 checkGLcall("glTexImage2D");
1981 glBindTexture(GL_TEXTURE_2D, 0);
1982 glDeleteTextures(1, &tmpTexture);
1986 f = fopen(filename, "w+");
1988 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
1989 return WINED3DERR_INVALIDCALL;
1991 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
1992 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2007 fwrite(&width,2,1,f);
2009 fwrite(&height,2,1,f);
2014 /* 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*/
2016 textureRow = allocatedMemory + (width * (height - 1) *4);
2018 textureRow = allocatedMemory;
2019 for (y = 0 ; y < height; y++) {
2020 for (i = 0; i < width; i++) {
2021 color = *((DWORD*)textureRow);
2022 fputc((color >> 16) & 0xFF, f); /* B */
2023 fputc((color >> 8) & 0xFF, f); /* G */
2024 fputc((color >> 0) & 0xFF, f); /* R */
2025 fputc((color >> 24) & 0xFF, f); /* A */
2028 /* take two rows of the pointer to the texture memory */
2030 (textureRow-= width << 3);
2033 TRACE("Closing file\n");
2037 IWineD3DSwapChain_Release(swapChain);
2039 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2043 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2044 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2045 This->Flags &= ~SFLAG_DIRTY;
2046 This->dirtyRect.left = This->currentDesc.Width;
2047 This->dirtyRect.top = This->currentDesc.Height;
2048 This->dirtyRect.right = 0;
2049 This->dirtyRect.bottom = 0;
2050 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2051 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2056 * Slightly inefficient way to handle multiple dirty rects but it works :)
2058 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2059 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2060 IWineD3DBaseTexture *baseTexture = NULL;
2061 This->Flags |= SFLAG_DIRTY;
2062 if (NULL != pDirtyRect) {
2063 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2064 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2065 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2066 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2068 This->dirtyRect.left = 0;
2069 This->dirtyRect.top = 0;
2070 This->dirtyRect.right = This->currentDesc.Width;
2071 This->dirtyRect.bottom = This->currentDesc.Height;
2073 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2074 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2075 /* if the container is a basetexture then mark it dirty. */
2076 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2077 TRACE("Passing to conatiner\n");
2078 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2079 IWineD3DBaseTexture_Release(baseTexture);
2084 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2085 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2087 TRACE("This %p, container %p\n", This, container);
2089 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2091 TRACE("Setting container to %p from %p\n", container, This->container);
2092 This->container = container;
2097 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2098 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2099 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2101 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2102 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2103 return WINED3DERR_INVALIDCALL;
2106 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2107 if (format == WINED3DFMT_UNKNOWN) {
2108 This->resource.size = 0;
2109 } else if (format == WINED3DFMT_DXT1) {
2110 /* DXT1 is half byte per pixel */
2111 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2113 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2114 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2115 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2117 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2118 This->resource.size *= This->pow2Height;
2122 /* Setup some glformat defaults */
2123 This->glDescription.glFormat = formatEntry->glFormat;
2124 This->glDescription.glFormatInternal = formatEntry->glInternal;
2125 This->glDescription.glType = formatEntry->glType;
2127 if (format != WINED3DFMT_UNKNOWN) {
2128 This->bytesPerPixel = formatEntry->bpp;
2129 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2131 This->bytesPerPixel = 0;
2135 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2137 This->resource.format = format;
2139 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);
2144 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2145 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2147 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2148 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2149 ERR("Not supported on render targets\n");
2150 return WINED3DERR_INVALIDCALL;
2153 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2154 WARN("Surface is locked or the HDC is in use\n");
2155 return WINED3DERR_INVALIDCALL;
2158 if(Mem && Mem != This->resource.allocatedMemory) {
2160 /* Do I have to copy the old surface content? */
2161 if(This->Flags & SFLAG_DIBSECTION) {
2162 /* Release the DC. No need to hold the critical section for the update
2163 * Thread because this thread runs only on front buffers, but this method
2164 * fails for render targets in the check above.
2166 SelectObject(This->hDC, This->dib.holdbitmap);
2167 DeleteDC(This->hDC);
2168 /* Release the DIB section */
2169 DeleteObject(This->dib.DIBsection);
2170 This->dib.bitmap_data = NULL;
2171 This->resource.allocatedMemory = NULL;
2173 This->Flags &= ~SFLAG_DIBSECTION;
2174 } else if(!(This->Flags & SFLAG_USERPTR)) {
2175 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2177 This->resource.allocatedMemory = Mem;
2178 This->Flags |= SFLAG_USERPTR;
2179 } else if(This->Flags & SFLAG_USERPTR) {
2180 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2181 This->resource.allocatedMemory = NULL;
2182 This->Flags &= ~SFLAG_USERPTR;
2187 /* TODO: replace this function with context management routines */
2188 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2189 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2192 This->Flags |= SFLAG_INPBUFFER;
2194 This->Flags &= ~SFLAG_INPBUFFER;
2198 This->Flags |= SFLAG_INTEXTURE;
2200 This->Flags &= ~SFLAG_INTEXTURE;
2206 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2207 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2208 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2209 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2211 /* Flipping is only supported on RenderTargets */
2212 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2215 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2216 * FIXME("(%p) Target override is not supported by now\n", This);
2217 * Additionally, it isn't really possible to support triple-buffering
2218 * properly on opengl at all
2222 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2223 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2226 /* Not called from the VTable */
2227 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2229 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2230 IWineD3DSwapChainImpl *swapchain = NULL;
2231 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2234 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2236 /* Get the swapchain. One of the surfaces has to be a primary surface */
2237 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2238 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2240 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2241 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2242 else return WINED3DERR_INVALIDCALL;
2248 rect.x1 = DestRect->left;
2249 rect.y1 = DestRect->top;
2250 rect.x2 = DestRect->right;
2251 rect.y2 = DestRect->bottom;
2255 rect.x2 = This->currentDesc.Width;
2256 rect.y2 = This->currentDesc.Height;
2259 /* Half-life does a Blt from the back buffer to the front buffer,
2260 * Full surface size, no flags... Use present instead
2264 /* First, check if we can do a Flip */
2266 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2268 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2269 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2276 /* Check the Destination rect and the surface sizes */
2278 (rect.x1 == 0) && (rect.y1 == 0) &&
2279 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2280 (This->currentDesc.Width == Src->currentDesc.Width) &&
2281 (This->currentDesc.Height == Src->currentDesc.Height)) {
2282 /* These flags are unimportant for the flag check, remove them */
2284 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2285 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2287 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2289 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2290 * take very long, while a flip is fast.
2291 * This applies to Half-Life, which does such Blts every time it finished
2292 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2293 * menu. This is also used by all apps when they do windowed rendering
2295 * The problem is that flipping is not really the same as copying. After a
2296 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2297 * untouched. Therefore it's necessary to override the swap effect
2298 * and to set it back after the flip.
2301 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2303 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2304 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2305 NULL, NULL, 0, NULL);
2307 swapchain->presentParms.SwapEffect = orig_swap;
2314 /* Blt from texture to rendertarget? */
2315 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2316 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2318 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2319 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2320 float glTexCoord[4];
2322 DDCOLORKEY oldBltCKey = {0,0};
2323 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2324 GLint oldStencil, oldNVRegisterCombiners = 0;
2327 RECT SourceRectangle;
2330 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2333 SourceRectangle.left = SrcRect->left;
2334 SourceRectangle.right = SrcRect->right;
2335 SourceRectangle.top = SrcRect->top;
2336 SourceRectangle.bottom = SrcRect->bottom;
2338 SourceRectangle.left = 0;
2339 SourceRectangle.right = Src->currentDesc.Width;
2340 SourceRectangle.top = 0;
2341 SourceRectangle.bottom = Src->currentDesc.Height;
2344 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2345 /* Fall back to software */
2346 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2347 SourceRectangle.left, SourceRectangle.top,
2348 SourceRectangle.right, SourceRectangle.bottom);
2349 return WINED3DERR_INVALIDCALL;
2352 /* Color keying: Check if we have to do a color keyed blt,
2353 * and if not check if a color key is activated.
2355 oldCKey = Src->CKeyFlags;
2356 if(!(Flags & DDBLT_KEYSRC) &&
2357 Src->CKeyFlags & DDSD_CKSRCBLT) {
2358 /* Ok, the surface has a color key, but we shall not use it -
2359 * Deactivate it for now, LoadTexture will catch this
2361 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2365 if(Flags & DDBLT_KEYDEST) {
2366 oldBltCKey = This->SrcBltCKey;
2367 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2368 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2370 This->SrcBltCKey = This->DestBltCKey;
2371 } else if (Flags & DDBLT_KEYSRC)
2372 oldBltCKey = This->SrcBltCKey;
2374 /* Now load the surface */
2375 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2379 /* Save all the old stuff until we have a proper opengl state manager */
2380 oldLight = glIsEnabled(GL_LIGHTING);
2381 oldFog = glIsEnabled(GL_FOG);
2382 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2383 oldBlend = glIsEnabled(GL_BLEND);
2384 oldCull = glIsEnabled(GL_CULL_FACE);
2385 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2386 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2388 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2389 oldNVRegisterCombiners = glIsEnabled(GL_REGISTER_COMBINERS_NV);
2392 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2393 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2394 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2395 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2397 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2398 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2399 TRACE("Drawing to front buffer\n");
2400 glDrawBuffer(GL_FRONT);
2401 checkGLcall("glDrawBuffer GL_FRONT");
2404 /* Unbind the old texture */
2405 glBindTexture(GL_TEXTURE_2D, 0);
2406 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
2408 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2409 /* We use texture unit 0 for blts */
2410 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2411 checkGLcall("glActiveTextureARB");
2413 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2416 /* Disable some fancy graphics effects */
2417 glDisable(GL_LIGHTING);
2418 checkGLcall("glDisable GL_LIGHTING");
2419 glDisable(GL_DEPTH_TEST);
2420 checkGLcall("glDisable GL_DEPTH_TEST");
2422 checkGLcall("glDisable GL_FOG");
2423 glDisable(GL_BLEND);
2424 checkGLcall("glDisable GL_BLEND");
2425 glDisable(GL_CULL_FACE);
2426 checkGLcall("glDisable GL_CULL_FACE");
2427 glDisable(GL_STENCIL_TEST);
2428 checkGLcall("glDisable GL_STENCIL_TEST");
2429 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2430 glDisable(GL_REGISTER_COMBINERS_NV);
2431 checkGLcall("glDisable GL_REGISTER_COMBINERS_NV");
2434 /* Ok, we need 2d textures, but not 1D or 3D */
2435 glDisable(GL_TEXTURE_1D);
2436 checkGLcall("glDisable GL_TEXTURE_1D");
2437 glEnable(GL_TEXTURE_2D);
2438 checkGLcall("glEnable GL_TEXTURE_2D");
2439 glDisable(GL_TEXTURE_3D);
2440 checkGLcall("glDisable GL_TEXTURE_3D");
2442 /* Bind the texture */
2443 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2444 checkGLcall("glBindTexture");
2446 glEnable(GL_SCISSOR_TEST);
2448 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2450 /* No filtering for blts */
2451 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2453 checkGLcall("glTexParameteri");
2454 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2456 checkGLcall("glTexParameteri");
2457 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2458 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2459 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2460 checkGLcall("glTexEnvi");
2462 /* This is for color keying */
2463 if(Flags & DDBLT_KEYSRC) {
2464 glEnable(GL_ALPHA_TEST);
2465 checkGLcall("glEnable GL_ALPHA_TEST");
2466 glAlphaFunc(GL_NOTEQUAL, 0.0);
2467 checkGLcall("glAlphaFunc\n");
2469 glDisable(GL_ALPHA_TEST);
2470 checkGLcall("glDisable GL_ALPHA_TEST");
2473 /* Draw a textured quad
2475 d3ddevice_set_ortho(This->resource.wineD3DDevice);
2479 glColor3d(1.0f, 1.0f, 1.0f);
2480 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2485 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2486 glVertex3f(rect.x1, rect.y2, 0.0);
2488 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2493 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2498 checkGLcall("glEnd");
2500 /* Unbind the texture */
2501 glBindTexture(GL_TEXTURE_2D, 0);
2502 checkGLcall("glEnable glBindTexture");
2504 /* Restore the old settings */
2506 glEnable(GL_LIGHTING);
2507 checkGLcall("glEnable GL_LIGHTING");
2511 checkGLcall("glEnable GL_FOG");
2514 glEnable(GL_DEPTH_TEST);
2515 checkGLcall("glEnable GL_DEPTH_TEST");
2519 checkGLcall("glEnable GL_BLEND");
2522 glEnable(GL_CULL_FACE);
2523 checkGLcall("glEnable GL_CULL_FACE");
2526 glEnable(GL_STENCIL_TEST);
2527 checkGLcall("glEnable GL_STENCIL_TEST");
2530 glDisable(GL_ALPHA_TEST);
2531 checkGLcall("glDisable GL_ALPHA_TEST");
2533 glEnable(GL_ALPHA_TEST);
2534 checkGLcall("glEnable GL_ALPHA_TEST");
2536 if (GL_SUPPORT(NV_REGISTER_COMBINERS) && oldNVRegisterCombiners) {
2537 glEnable(GL_REGISTER_COMBINERS_NV);
2538 checkGLcall("glEnable GL_REGISTER_COMBINERS_NV");
2541 glAlphaFunc(alphafunc, alpharef);
2542 checkGLcall("glAlphaFunc\n");
2544 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2545 glDrawBuffer(oldDraw);
2548 /* Restore the color key flags */
2549 if(oldCKey != Src->CKeyFlags) {
2550 Src->CKeyFlags = oldCKey;
2553 /* Restore the old color key */
2554 if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
2555 This->SrcBltCKey = oldBltCKey;
2559 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2560 This->Flags |= SFLAG_GLDIRTY;
2566 /* Blt from rendertarget to texture? */
2567 if( (SrcSurface == swapchain->frontBuffer) ||
2568 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2569 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2570 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2575 TRACE("Blt from rendertarget to texture\n");
2577 /* Call preload for the surface to make sure it isn't dirty */
2578 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2581 srect.x1 = SrcRect->left;
2582 srect.y1 = SrcRect->top;
2583 srect.x2 = SrcRect->right;
2584 srect.y2 = SrcRect->bottom;
2588 srect.x2 = Src->currentDesc.Width;
2589 srect.y2 = Src->currentDesc.Height;
2594 /* Bind the target texture */
2595 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2596 checkGLcall("glBindTexture");
2597 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2598 glReadBuffer(GL_BACK);
2600 glReadBuffer(GL_FRONT);
2602 checkGLcall("glReadBuffer");
2604 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2605 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2607 /* I have to process this row by row to swap the image,
2608 * otherwise it would be upside down, so streching in y direction
2609 * doesn't cost extra time
2611 * However, streching in x direction can be avoided if not necessary
2613 for(row = rect.y1; row < rect.y2; row++) {
2614 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2615 /* Well, that stuff works, but it's very slow.
2616 * find a better way instead
2619 for(col = rect.x1; col < rect.x2; col++) {
2620 glCopyTexSubImage2D(GL_TEXTURE_2D,
2622 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2623 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2627 glCopyTexSubImage2D(GL_TEXTURE_2D,
2629 rect.x1, rect.y2 + rect.y1 - row - 1, /* xoffset, yoffset */
2630 srect.x1, row - rect.y1,
2631 rect.x2-rect.x1, 1);
2635 vcheckGLcall("glCopyTexSubImage2D");
2638 if(!(This->Flags & SFLAG_DONOTFREE)) {
2639 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2640 This->resource.allocatedMemory = NULL;
2642 This->Flags |= SFLAG_GLDIRTY;
2650 if (Flags & DDBLT_COLORFILL) {
2651 /* This is easy to handle for the D3D Device... */
2653 IWineD3DSwapChainImpl *implSwapChain;
2655 TRACE("Colorfill\n");
2657 /* The color as given in the Blt function is in the format of the frame-buffer...
2658 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2660 if (This->resource.format == WINED3DFMT_P8) {
2661 if (This->palette) {
2662 color = ((0xFF000000) |
2663 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2664 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2665 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2670 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2671 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2674 color = ((0xFF000000) |
2675 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2676 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2677 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2680 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2681 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2682 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2684 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2685 color = DDBltFx->u5.dwFillColor;
2688 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2689 return WINED3DERR_INVALIDCALL;
2692 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2693 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2694 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2695 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2696 glDrawBuffer(GL_BACK);
2697 checkGLcall("glDrawBuffer(GL_BACK)");
2699 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2700 glDrawBuffer(GL_FRONT);
2701 checkGLcall("glDrawBuffer(GL_FRONT)");
2704 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2705 return WINED3DERR_INVALIDCALL;
2708 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2710 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2711 1 /* Number of rectangles */,
2713 WINED3DCLEAR_TARGET,
2718 /* Restore the original draw buffer */
2719 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2720 glDrawBuffer(GL_BACK);
2721 vcheckGLcall("glDrawBuffer");
2727 /* Default: Fall back to the generic blt */
2728 return WINED3DERR_INVALIDCALL;
2731 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2732 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2733 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2734 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2735 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2737 /* Special cases for RenderTargets */
2738 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2739 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2740 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2743 /* For the rest call the X11 surface implementation.
2744 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2745 * other Blts are rather rare
2747 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2750 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2751 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2752 TRACE("(%p)->(%x)\n", This, Flags);
2757 case DDGBS_ISBLTDONE:
2761 return DDERR_INVALIDPARAMS;
2765 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2766 /* XXX: DDERR_INVALIDSURFACETYPE */
2768 TRACE("(%p)->(%08x)\n",iface,Flags);
2771 case DDGFS_ISFLIPDONE:
2775 return DDERR_INVALIDPARAMS;
2779 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2780 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2781 TRACE("(%p)\n", This);
2783 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2786 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2787 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2788 TRACE("(%p)\n", This);
2790 /* So far we don't lose anything :) */
2791 This->Flags &= ~SFLAG_LOST;
2795 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2796 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2797 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2798 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2800 /* Special cases for RenderTargets */
2801 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2802 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2804 RECT SrcRect, DstRect;
2808 SrcRect.left = rsrc->left;
2809 SrcRect.top= rsrc->top;
2810 SrcRect.bottom = rsrc->bottom;
2811 SrcRect.right = rsrc->right;
2815 SrcRect.right = srcImpl->currentDesc.Width;
2816 SrcRect.bottom = srcImpl->currentDesc.Height;
2819 DstRect.left = dstx;
2821 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2822 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2824 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2825 if(trans & DDBLTFAST_SRCCOLORKEY)
2826 Flags |= DDBLT_KEYSRC;
2827 if(trans & DDBLTFAST_DESTCOLORKEY)
2828 Flags |= DDBLT_KEYDEST;
2829 if(trans & DDBLTFAST_WAIT)
2830 Flags |= DDBLT_WAIT;
2831 if(trans & DDBLTFAST_DONOTWAIT)
2832 Flags |= DDBLT_DONOTWAIT;
2834 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2838 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2841 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2842 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2843 TRACE("(%p)->(%p)\n", This, Pal);
2845 *Pal = (IWineD3DPalette *) This->palette;
2849 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2850 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2852 IWineD3DPaletteImpl *pal = This->palette;
2854 TRACE("(%p)\n", This);
2856 if(This->resource.format == WINED3DFMT_P8 ||
2857 This->resource.format == WINED3DFMT_A8P8)
2859 TRACE("Dirtifying surface\n");
2860 This->Flags |= SFLAG_DIRTY;
2863 if(This->Flags & SFLAG_DIBSECTION) {
2864 TRACE("(%p): Updating the hdc's palette\n", This);
2865 for (n=0; n<256; n++) {
2867 col[n].rgbRed = pal->palents[n].peRed;
2868 col[n].rgbGreen = pal->palents[n].peGreen;
2869 col[n].rgbBlue = pal->palents[n].peBlue;
2871 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2872 /* Use the default device palette */
2873 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2874 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2875 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2877 col[n].rgbReserved = 0;
2879 SetDIBColorTable(This->hDC, 0, 256, col);
2885 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2886 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2887 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2888 TRACE("(%p)->(%p)\n", This, Pal);
2890 if(This->palette != NULL)
2891 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2892 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2894 if(PalImpl != NULL) {
2895 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2896 /* Set the device's main palette if the palette
2897 * wasn't a primary palette before
2899 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2900 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2903 for(i=0; i < 256; i++) {
2904 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2908 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2911 This->palette = PalImpl;
2913 return IWineD3DSurface_RealizePalette(iface);
2916 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2917 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2918 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
2920 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2921 FIXME(" colorkey value not supported (%08x) !\n", Flags);
2922 return DDERR_INVALIDPARAMS;
2925 /* Dirtify the surface, but only if a key was changed */
2927 switch (Flags & ~DDCKEY_COLORSPACE) {
2928 case DDCKEY_DESTBLT:
2929 This->DestBltCKey = *CKey;
2930 This->CKeyFlags |= DDSD_CKDESTBLT;
2933 case DDCKEY_DESTOVERLAY:
2934 This->DestOverlayCKey = *CKey;
2935 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2938 case DDCKEY_SRCOVERLAY:
2939 This->SrcOverlayCKey = *CKey;
2940 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2944 This->SrcBltCKey = *CKey;
2945 This->CKeyFlags |= DDSD_CKSRCBLT;
2950 switch (Flags & ~DDCKEY_COLORSPACE) {
2951 case DDCKEY_DESTBLT:
2952 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2955 case DDCKEY_DESTOVERLAY:
2956 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2959 case DDCKEY_SRCOVERLAY:
2960 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2964 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2972 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2973 /** Check against the maximum texture sizes supported by the video card **/
2974 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2976 TRACE("%p\n", This);
2977 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2978 /* one of three options
2979 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)
2980 2: Set the texture to the maxium size (bad idea)
2981 3: WARN and return WINED3DERR_NOTAVAILABLE;
2982 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.
2984 WARN("(%p) Creating an oversized surface\n", This);
2985 This->Flags |= SFLAG_OVERSIZE;
2987 /* This will be initialized on the first blt */
2988 This->glRect.left = 0;
2989 This->glRect.top = 0;
2990 This->glRect.right = 0;
2991 This->glRect.bottom = 0;
2993 /* No oversize, gl rect is the full texture size */
2994 This->Flags &= ~SFLAG_OVERSIZE;
2995 This->glRect.left = 0;
2996 This->glRect.top = 0;
2997 This->glRect.right = This->pow2Width;
2998 This->glRect.bottom = This->pow2Height;
3004 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3005 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3007 TRACE("(%p)\n", This);
3009 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3010 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3011 ie pitch = (width/4) * bytes per block */
3012 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3013 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3014 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3015 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3016 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3018 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3019 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3020 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3022 ret = This->bytesPerPixel * This->pow2Width;
3024 /* Surfaces are 32 bit aligned */
3025 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3027 TRACE("(%p) Returning %d\n", This, ret);
3031 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3032 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3034 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3036 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3038 TRACE("(%p): Not an overlay surface\n", This);
3039 return DDERR_NOTAOVERLAYSURFACE;
3045 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3046 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3048 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3050 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3052 TRACE("(%p): Not an overlay surface\n", This);
3053 return DDERR_NOTAOVERLAYSURFACE;
3059 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3060 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3061 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3063 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3065 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3067 TRACE("(%p): Not an overlay surface\n", This);
3068 return DDERR_NOTAOVERLAYSURFACE;
3074 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3075 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3076 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3077 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3079 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3081 TRACE("(%p): Not an overlay surface\n", This);
3082 return DDERR_NOTAOVERLAYSURFACE;
3088 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3091 IWineD3DSurfaceImpl_QueryInterface,
3092 IWineD3DSurfaceImpl_AddRef,
3093 IWineD3DSurfaceImpl_Release,
3094 /* IWineD3DResource */
3095 IWineD3DSurfaceImpl_GetParent,
3096 IWineD3DSurfaceImpl_GetDevice,
3097 IWineD3DSurfaceImpl_SetPrivateData,
3098 IWineD3DSurfaceImpl_GetPrivateData,
3099 IWineD3DSurfaceImpl_FreePrivateData,
3100 IWineD3DSurfaceImpl_SetPriority,
3101 IWineD3DSurfaceImpl_GetPriority,
3102 IWineD3DSurfaceImpl_PreLoad,
3103 IWineD3DSurfaceImpl_GetType,
3104 /* IWineD3DSurface */
3105 IWineD3DSurfaceImpl_GetContainer,
3106 IWineD3DSurfaceImpl_GetDesc,
3107 IWineD3DSurfaceImpl_LockRect,
3108 IWineD3DSurfaceImpl_UnlockRect,
3109 IWineD3DSurfaceImpl_GetDC,
3110 IWineD3DSurfaceImpl_ReleaseDC,
3111 IWineD3DSurfaceImpl_Flip,
3112 IWineD3DSurfaceImpl_Blt,
3113 IWineD3DSurfaceImpl_GetBltStatus,
3114 IWineD3DSurfaceImpl_GetFlipStatus,
3115 IWineD3DSurfaceImpl_IsLost,
3116 IWineD3DSurfaceImpl_Restore,
3117 IWineD3DSurfaceImpl_BltFast,
3118 IWineD3DSurfaceImpl_GetPalette,
3119 IWineD3DSurfaceImpl_SetPalette,
3120 IWineD3DSurfaceImpl_RealizePalette,
3121 IWineD3DSurfaceImpl_SetColorKey,
3122 IWineD3DSurfaceImpl_GetPitch,
3123 IWineD3DSurfaceImpl_SetMem,
3124 IWineD3DSurfaceImpl_SetOverlayPosition,
3125 IWineD3DSurfaceImpl_GetOverlayPosition,
3126 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3127 IWineD3DSurfaceImpl_UpdateOverlay,
3129 IWineD3DSurfaceImpl_CleanDirtyRect,
3130 IWineD3DSurfaceImpl_AddDirtyRect,
3131 IWineD3DSurfaceImpl_LoadTexture,
3132 IWineD3DSurfaceImpl_SaveSnapshot,
3133 IWineD3DSurfaceImpl_SetContainer,
3134 IWineD3DSurfaceImpl_SetPBufferState,
3135 IWineD3DSurfaceImpl_SetGlTextureDesc,
3136 IWineD3DSurfaceImpl_GetGlDesc,
3137 IWineD3DSurfaceImpl_GetData,
3138 IWineD3DSurfaceImpl_SetFormat,
3139 IWineD3DSurfaceImpl_PrivateSetup