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
11 * Copyright 2007 Henri Verbeet
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include "wine/port.h"
30 #include "wined3d_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
33 #define GLINFO_LOCATION This->resource.wineD3DDevice->adapter->gl_info
55 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf);
57 static void surface_download_data(IWineD3DSurfaceImpl *This) {
58 if (!This->resource.allocatedMemory) This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, This->resource.size + 4);
59 if (This->resource.format == WINED3DFMT_DXT1 ||
60 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
61 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
62 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* We can assume this as the texture would not have been created otherwise */
63 FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
65 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
66 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
68 GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory));
69 checkGLcall("glGetCompressedTexImageARB()");
76 if(This->Flags & SFLAG_CONVERTED) {
77 FIXME("Read back converted textures unsupported\n");
81 if (This->Flags & SFLAG_NONPOW2) {
82 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
83 src_pitch = This->bytesPerPixel * This->pow2Width;
84 dst_pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This);
85 src_pitch = (src_pitch + alignment - 1) & ~(alignment - 1);
86 mem = HeapAlloc(GetProcessHeap(), 0, src_pitch * This->pow2Height);
88 mem = This->resource.allocatedMemory;
91 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
92 This->glDescription.glFormat, This->glDescription.glType, mem);
94 glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
95 This->glDescription.glType, mem);
96 checkGLcall("glGetTexImage()");
98 if (This->Flags & SFLAG_NONPOW2) {
99 LPBYTE src_data, dst_data;
102 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
103 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
104 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
106 * We're doing this...
108 * instead of boxing the texture :
109 * |<-texture width ->| -->pow2width| /\
110 * |111111111111111111| | |
111 * |222 Texture 222222| boxed empty | texture height
112 * |3333 Data 33333333| | |
113 * |444444444444444444| | \/
114 * ----------------------------------- |
115 * | boxed empty | boxed empty | pow2height
117 * -----------------------------------
120 * we're repacking the data to the expected texture width
122 * |<-texture width ->| -->pow2width| /\
123 * |111111111111111111222222222222222| |
124 * |222333333333333333333444444444444| texture height
128 * | empty | pow2height
130 * -----------------------------------
134 * |<-texture width ->| /\
135 * |111111111111111111|
136 * |222222222222222222|texture height
137 * |333333333333333333|
138 * |444444444444444444| \/
139 * --------------------
141 * this also means that any references to allocatedMemory should work with the data as if were a
142 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
144 * internally the texture is still stored in a boxed format so any references to textureName will
145 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
147 * Performance should not be an issue, because applications normally do not lock the surfaces when
148 * rendering. If an app does, the SFLAG_DYNLOCK flag will kick in and the memory copy won't be released,
149 * and doesn't have to be re-read.
152 dst_data = This->resource.allocatedMemory;
153 TRACE("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
154 for (y = 1 ; y < This->currentDesc.Height; y++) {
155 /* skip the first row */
156 src_data += src_pitch;
157 dst_data += dst_pitch;
158 memcpy(dst_data, src_data, dst_pitch);
161 HeapFree(GetProcessHeap(), 0, mem);
164 /* Surface has now been downloaded */
165 This->Flags |= SFLAG_INSYSMEM;
168 static void surface_upload_data(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data) {
169 if (This->resource.format == WINED3DFMT_DXT1 ||
170 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
171 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
172 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
173 FIXME("Using DXT1/3/5 without advertized support\n");
175 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
176 /* Neither NONPOW2, DIBSECTION nor OVERSIZE flags can be set on compressed textures */
177 This->Flags |= SFLAG_CLIENT;
180 TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data);
182 /* glCompressedTexSubImage2D for uploading and glTexImage2D for allocating does not work well on some drivers(r200 dri, MacOS ATI driver)
183 * glCompressedTexImage2D does not accept NULL pointers. So for compressed textures surface_allocate_surface does nothing, and this
184 * function uses glCompressedTexImage2D instead of the SubImage call
186 GL_EXTCALL(glCompressedTexImage2DARB(This->glDescription.target, This->glDescription.level, internal,
187 width, height, 0 /* border */, This->resource.size, data));
188 checkGLcall("glCompressedTexSubImage2D");
192 TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This, width, height, data);
194 glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data);
195 checkGLcall("glTexSubImage2D");
200 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) {
201 BOOL enable_client_storage = FALSE;
203 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,
204 This->glDescription.target, This->glDescription.level, debug_d3dformat(This->resource.format), internal, width, height, format, type);
206 if (This->resource.format == WINED3DFMT_DXT1 ||
207 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
208 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
209 /* glCompressedTexImage2D does not accept NULL pointers, so we cannot allocate a compressed texture without uploading data */
210 TRACE("Not allocating compressed surfaces, surface_upload_data will specify them\n");
216 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
217 if(This->Flags & (SFLAG_NONPOW2 | SFLAG_DIBSECTION | SFLAG_OVERSIZE | SFLAG_CONVERTED) || This->resource.allocatedMemory == NULL) {
218 /* In some cases we want to disable client storage.
219 * SFLAG_NONPOW2 has a bigger opengl texture than the client memory, and different pitches
220 * SFLAG_DIBSECTION: Dibsections may have read / write protections on the memory. Avoid issues...
221 * SFLAG_OVERSIZE: The gl texture is smaller than the allocated memory
222 * SFLAG_CONVERTED: The conversion destination memory is freed after loading the surface
223 * allocatedMemory == NULL: Not defined in the extension. Seems to disable client storage effectively
225 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
226 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
227 This->Flags &= SFLAG_CLIENT;
228 enable_client_storage = TRUE;
230 This->Flags |= SFLAG_CLIENT;
231 /* Below point opengl to our allocated texture memory */
234 glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type,
235 This->Flags & SFLAG_CLIENT ? This->resource.allocatedMemory : NULL);
236 checkGLcall("glTexImage2D");
238 if(enable_client_storage) {
239 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
240 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
244 This->Flags |= SFLAG_ALLOCATED;
247 /* In D3D the depth stencil dimensions have to be greater than or equal to the
248 * render target dimensions. With FBOs, the dimensions have to be an exact match. */
249 /* TODO: We should synchronize the renderbuffer's content with the texture's content. */
250 void surface_set_compatible_renderbuffer(IWineD3DSurface *iface, unsigned int width, unsigned int height) {
251 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
252 renderbuffer_entry_t *entry;
253 GLuint renderbuffer = 0;
254 unsigned int src_width, src_height;
256 src_width = This->pow2Width;
257 src_height = This->pow2Height;
259 /* A depth stencil smaller than the render target is not valid */
260 if (width > src_width || height > src_height) return;
262 /* Remove any renderbuffer set if the sizes match */
263 if (width == src_width && height == src_height) {
264 This->current_renderbuffer = NULL;
268 /* Look if we've already got a renderbuffer of the correct dimensions */
269 LIST_FOR_EACH_ENTRY(entry, &This->renderbuffers, renderbuffer_entry_t, entry) {
270 if (entry->width == width && entry->height == height) {
271 renderbuffer = entry->id;
272 This->current_renderbuffer = entry;
278 const GlPixelFormatDesc *glDesc;
279 getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc);
281 GL_EXTCALL(glGenRenderbuffersEXT(1, &renderbuffer));
282 GL_EXTCALL(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, renderbuffer));
283 GL_EXTCALL(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, glDesc->glFormat, width, height));
285 entry = HeapAlloc(GetProcessHeap(), 0, sizeof(renderbuffer_entry_t));
286 entry->width = width;
287 entry->height = height;
288 entry->id = renderbuffer;
289 list_add_head(&This->renderbuffers, &entry->entry);
291 This->current_renderbuffer = entry;
294 checkGLcall("set_compatible_renderbuffer");
297 GLenum surface_get_gl_buffer(IWineD3DSurface *iface, IWineD3DSwapChain *swapchain) {
298 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
299 IWineD3DSwapChainImpl *swapchain_impl = (IWineD3DSwapChainImpl *)swapchain;
301 TRACE("(%p) : swapchain %p\n", This, swapchain);
303 if (swapchain_impl->backBuffer && swapchain_impl->backBuffer[0] == iface) {
304 TRACE("Returning GL_BACK\n");
306 } else if (swapchain_impl->frontBuffer == iface) {
307 TRACE("Returning GL_FRONT\n");
311 FIXME("Higher back buffer, returning GL_BACK\n");
315 /* *******************************************
316 IWineD3DSurface IUnknown parts follow
317 ******************************************* */
318 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
320 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
321 /* Warn ,but be nice about things */
322 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
324 if (IsEqualGUID(riid, &IID_IUnknown)
325 || IsEqualGUID(riid, &IID_IWineD3DBase)
326 || IsEqualGUID(riid, &IID_IWineD3DResource)
327 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
328 IUnknown_AddRef((IUnknown*)iface);
333 return E_NOINTERFACE;
336 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
337 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
338 ULONG ref = InterlockedIncrement(&This->resource.ref);
339 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
343 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
344 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
345 ULONG ref = InterlockedDecrement(&This->resource.ref);
346 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
348 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
349 renderbuffer_entry_t *entry, *entry2;
350 TRACE("(%p) : cleaning up\n", This);
352 if(iface == device->lastActiveRenderTarget) {
353 IWineD3DSwapChainImpl *swapchain = device->swapchains ? (IWineD3DSwapChainImpl *) device->swapchains[0] : NULL;
355 TRACE("Last active render target destroyed\n");
356 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
357 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
358 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
359 * and the lastActiveRenderTarget member shouldn't matter
362 ENTER_GL(); /* For ActivateContext */
363 if(swapchain->backBuffer && swapchain->backBuffer[0] != iface) {
364 TRACE("Activating primary back buffer\n");
365 ActivateContext(device, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
366 } else if(!swapchain->backBuffer && swapchain->frontBuffer != iface) {
367 /* Single buffering environment */
368 TRACE("Activating primary front buffer\n");
369 ActivateContext(device, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
371 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
372 /* Implicit render target destroyed, that means the device is being destroyed
373 * whatever we set here, it shouldn't matter
375 device->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
379 /* May happen during ddraw uninitialization */
380 TRACE("Render target set, but swapchain does not exist!\n");
381 device->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
385 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
388 /* Need a context to destroy the texture. Use the currently active render target, but only if
389 * the primary render target exists. Otherwise lastActiveRenderTarget is garbage, see above.
390 * When destroying the primary rt, Uninit3D will activate a context before doing anything
392 if(device->render_targets[0]) {
393 ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
396 TRACE("Deleting texture %d\n", This->glDescription.textureName);
397 glDeleteTextures(1, &This->glDescription.textureName);
401 if(This->Flags & SFLAG_DIBSECTION) {
403 SelectObject(This->hDC, This->dib.holdbitmap);
405 /* Release the DIB section */
406 DeleteObject(This->dib.DIBsection);
407 This->dib.bitmap_data = NULL;
408 This->resource.allocatedMemory = NULL;
410 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
412 HeapFree(GetProcessHeap(), 0, This->palette9);
414 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
415 if(iface == device->ddraw_primary)
416 device->ddraw_primary = NULL;
418 LIST_FOR_EACH_ENTRY_SAFE(entry, entry2, &This->renderbuffers, renderbuffer_entry_t, entry) {
419 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &entry->id));
420 HeapFree(GetProcessHeap(), 0, entry);
423 TRACE("(%p) Released\n", This);
424 HeapFree(GetProcessHeap(), 0, This);
430 /* ****************************************************
431 IWineD3DSurface IWineD3DResource parts follow
432 **************************************************** */
433 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
434 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
437 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
438 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
441 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
442 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
445 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
446 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
449 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
450 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
453 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
454 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
457 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
458 /* TODO: check for locks */
459 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
460 IWineD3DBaseTexture *baseTexture = NULL;
461 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
463 TRACE("(%p)Checking to see if the container is a base texture\n", This);
464 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
465 TRACE("Passing to container\n");
466 IWineD3DBaseTexture_PreLoad(baseTexture);
467 IWineD3DBaseTexture_Release(baseTexture);
469 TRACE("(%p) : About to load surface\n", This);
472 if(!device->isInDraw) {
473 ActivateContext(device, device->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
476 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
477 if (!This->glDescription.level) {
478 if (!This->glDescription.textureName) {
479 glGenTextures(1, &This->glDescription.textureName);
480 checkGLcall("glGenTextures");
481 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
483 glBindTexture(This->glDescription.target, This->glDescription.textureName);
484 checkGLcall("glBindTexture");
485 IWineD3DSurface_LoadTexture(iface, FALSE);
486 /* This is where we should be reducing the amount of GLMemoryUsed */
487 } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
488 /* assume this is a coding error not a real error for now */
489 FIXME("Mipmap surface has a glTexture bound to it!\n");
491 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
492 /* Tell opengl to try and keep this texture in video ram (well mostly) */
495 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
502 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
503 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
504 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
507 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
508 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
509 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
512 /* ******************************************************
513 IWineD3DSurface IWineD3DSurface parts follow
514 ****************************************************** */
516 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
517 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
518 IWineD3DBase *container = 0;
520 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
523 ERR("Called without a valid ppContainer.\n");
527 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
528 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
529 * GetContainer will return the Direct3D device used to create the surface.
531 if (This->container) {
532 container = This->container;
534 container = (IWineD3DBase *)This->resource.wineD3DDevice;
537 TRACE("Relaying to QueryInterface\n");
538 return IUnknown_QueryInterface(container, riid, ppContainer);
541 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
542 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
544 TRACE("(%p) : copying into %p\n", This, pDesc);
545 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
546 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
547 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
548 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
549 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
550 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
551 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
552 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
553 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
557 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
558 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
559 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
560 if (This->glDescription.textureName == 0 && textureName != 0) {
561 This->Flags &= ~SFLAG_INTEXTURE;
562 IWineD3DSurface_AddDirtyRect(iface, NULL);
564 This->glDescription.textureName = textureName;
565 This->glDescription.target = target;
566 This->Flags &= ~SFLAG_ALLOCATED;
569 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
570 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
571 TRACE("(%p) : returning %p\n", This, &This->glDescription);
572 *glDescription = &This->glDescription;
575 /* TODO: think about moving this down to resource? */
576 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
577 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
578 /* 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 future */
579 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
580 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
582 return (CONST void*)(This->resource.allocatedMemory);
585 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch, BOOL srcUpsideDown) {
589 BYTE *row, *top, *bottom;
593 switch(This->resource.format)
597 /* GL can't return palettized data, so read ARGB pixels into a
598 * separate block of memory and convert them into palettized format
599 * in software. Slow, but if the app means to use palettized render
600 * targets and locks it...
602 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
603 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
604 * for the color channels when palettizing the colors.
607 type = GL_UNSIGNED_BYTE;
609 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * 3);
611 ERR("Out of memory\n");
614 bpp = This->bytesPerPixel * 3;
620 fmt = This->glDescription.glFormat;
621 type = This->glDescription.glType;
622 bpp = This->bytesPerPixel;
625 glReadPixels(rect->left, rect->top,
626 rect->right - rect->left,
627 rect->bottom - rect->top,
629 vcheckGLcall("glReadPixels");
631 /* TODO: Merge this with the palettization loop below for P8 targets */
635 /* glReadPixels returns the image upside down, and there is no way to prevent this.
636 Flip the lines in software */
637 len = (rect->right - rect->left) * bpp;
638 off = rect->left * bpp;
640 row = HeapAlloc(GetProcessHeap(), 0, len);
642 ERR("Out of memory\n");
643 if(This->resource.format == WINED3DFMT_P8) HeapFree(GetProcessHeap(), 0, mem);
647 top = mem + pitch * rect->top;
648 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
649 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
650 memcpy(row, top + off, len);
651 memcpy(top + off, bottom + off, len);
652 memcpy(bottom + off, row, len);
656 HeapFree(GetProcessHeap(), 0, row);
659 if(This->resource.format == WINED3DFMT_P8) {
661 DWORD width = pitch / 3;
664 pal = This->palette->palents;
666 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
669 for(y = rect->top; y < rect->bottom; y++) {
670 for(x = rect->left; x < rect->right; x++) {
671 /* start lines pixels */
672 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
673 BYTE *green = blue + 1;
674 BYTE *red = green + 1;
676 for(c = 0; c < 256; c++) {
677 if(*red == pal[c].peRed &&
678 *green == pal[c].peGreen &&
679 *blue == pal[c].peBlue)
681 *((BYTE *) dest + y * width + x) = c;
687 HeapFree(GetProcessHeap(), 0, mem);
691 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
692 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
693 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
694 IWineD3DSwapChainImpl *swapchain = NULL;
696 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
698 if (!(This->Flags & SFLAG_LOCKABLE)) {
699 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
700 texture regions, and since the destination is an unlockable region we need
702 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
703 /*return WINED3DERR_INVALIDCALL; */
706 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
708 /* Mark the surface locked */
709 This->Flags |= SFLAG_LOCKED;
711 /* Whatever surface we have, make sure that there is memory allocated for the downloaded copy */
712 if(!This->resource.allocatedMemory) {
713 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->resource.size + 4);
714 This->Flags &= ~SFLAG_INSYSMEM; /* This is the marker that surface data has to be downloaded */
717 /* Calculate the correct start address to report */
719 pLockedRect->pBits = This->resource.allocatedMemory;
720 This->lockedRect.left = 0;
721 This->lockedRect.top = 0;
722 This->lockedRect.right = This->currentDesc.Width;
723 This->lockedRect.bottom = This->currentDesc.Height;
724 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);
726 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
728 /* DXTn textures are based on compressed blocks of 4x4 pixels, each
729 * 16 bytes large (8 bytes in case of DXT1). Because of that Pitch has
730 * slightly different meaning compared to regular textures. For DXTn
731 * textures Pitch is the size of a row of blocks, 4 high and "width"
732 * long. The x offset is calculated differently as well, since moving 4
733 * pixels to the right actually moves an entire 4x4 block to right, ie
734 * 16 bytes (8 in case of DXT1). */
735 if (This->resource.format == WINED3DFMT_DXT1) {
736 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 2);
737 } else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3
738 || This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
739 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top / 4) + (pRect->left * 4);
741 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
743 This->lockedRect.left = pRect->left;
744 This->lockedRect.top = pRect->top;
745 This->lockedRect.right = pRect->right;
746 This->lockedRect.bottom = pRect->bottom;
749 if (This->Flags & SFLAG_NONPOW2) {
750 TRACE("Locking non-power 2 texture\n");
753 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
754 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
757 if(!(This->Flags & SFLAG_DYNLOCK)) {
759 /* MAXLOCKCOUNT is defined in wined3d_private.h */
760 if(This->lockCount > MAXLOCKCOUNT) {
761 TRACE("Surface is locked regularly, not freeing the system memory copy any more\n");
762 This->Flags |= SFLAG_DYNLOCK;
766 if (Flags & WINED3DLOCK_DISCARD) {
767 /* Set SFLAG_INSYSMEM, so we'll never try to download the data from the texture. */
768 TRACE("WINED3DLOCK_DISCARD flag passed, marking local copy as up to date\n");
769 This->Flags |= SFLAG_INSYSMEM;
772 if (This->Flags & SFLAG_INSYSMEM) {
773 TRACE("Local copy is up to date, not downloading data\n");
777 /* Now download the surface content from opengl
778 * Use the render target readback if the surface is on a swapchain(=onscreen render target) or the current primary target
779 * Offscreen targets which are not active at the moment or are higher targets(fbos) can be locked with the texture path
781 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
782 if(swapchain || iface == myDevice->render_targets[0]) {
783 BOOL srcIsUpsideDown;
785 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
786 static BOOL warned = FALSE;
788 ERR("The application tries to lock the render target, but render target locking is disabled\n");
791 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
795 /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
796 * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
797 * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
798 * context->last_was_blit set on the unlock.
801 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
803 /* Select the correct read buffer, and give some debug output.
804 * There is no need to keep track of the current read buffer or reset it, every part of the code
805 * that reads sets the read buffer as desired.
808 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
809 * Read from the back buffer
811 TRACE("Locking offscreen render target\n");
812 glReadBuffer(myDevice->offscreenBuffer);
813 srcIsUpsideDown = TRUE;
815 GLenum buffer = surface_get_gl_buffer(iface, (IWineD3DSwapChain *)swapchain);
816 TRACE("Locking %#x buffer\n", buffer);
817 glReadBuffer(buffer);
818 checkGLcall("glReadBuffer");
820 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
821 srcIsUpsideDown = FALSE;
824 switch(wined3d_settings.rendertargetlock_mode) {
828 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
833 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
834 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
839 /* Mark the local copy up to date if a full download was done */
840 if(This->lockedRect.left == 0 &&
841 This->lockedRect.top == 0 &&
842 This->lockedRect.right == This->currentDesc.Width &&
843 This->lockedRect.bottom == This->currentDesc.Height) {
844 This->Flags |= SFLAG_INSYSMEM;
846 } else if(iface == myDevice->stencilBufferTarget) {
847 /** the depth stencil in openGL has a format of GL_FLOAT
848 * which should be good for WINED3DFMT_D16_LOCKABLE
850 * it is unclear what format the stencil buffer is in except.
851 * 'Each index is converted to fixed point...
852 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
853 * mappings in the table GL_PIXEL_MAP_S_TO_S.
854 * glReadPixels(This->lockedRect.left,
855 * This->lockedRect.bottom - j - 1,
856 * This->lockedRect.right - This->lockedRect.left,
858 * GL_DEPTH_COMPONENT,
860 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
862 * Depth Stencil surfaces which are not the current depth stencil target should have their data in a
863 * gl texture(next path), or in local memory(early return because of set SFLAG_INSYSMEM above). If
864 * none of that is the case the problem is not in this function :-)
865 ********************************************/
866 FIXME("Depth stencil locking not supported yet\n");
868 /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */
869 TRACE("locking an ordinary surface\n");
871 if (0 != This->glDescription.textureName) {
872 /* Now I have to copy thing bits back */
876 if(myDevice->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
877 ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
880 /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
881 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
882 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
883 checkGLcall("glActiveTextureARB");
885 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
886 IWineD3DSurface_PreLoad(iface);
888 surface_download_data(This);
894 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
897 IWineD3DBaseTexture *pBaseTexture;
900 * as seen in msdn docs
902 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
904 /** Dirtify Container if needed */
905 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
906 TRACE("Making container dirty\n");
907 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
908 IWineD3DBaseTexture_Release(pBaseTexture);
910 TRACE("Surface is standalone, no need to dirty the container\n");
914 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch,
915 This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
919 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
921 GLint prev_rasterpos[4];
923 BOOL storechanged = FALSE, memory_allocated = FALSE;
927 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
929 glDisable(GL_TEXTURE_2D);
930 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
933 vcheckGLcall("glFlush");
934 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
935 vcheckGLcall("glIntegerv");
936 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
937 vcheckGLcall("glIntegerv");
938 glPixelZoom(1.0, -1.0);
939 vcheckGLcall("glPixelZoom");
941 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
942 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
943 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
945 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
946 vcheckGLcall("glRasterPos2f");
948 /* Some drivers(radeon dri, others?) don't like exceptions during
949 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
950 * after ReleaseDC. Reading it will cause an exception, which x11drv will
951 * catch to put the dib section in InSync mode, which leads to a crash
952 * and a blocked x server on my radeon card.
954 * The following lines read the dib section so it is put in inSync mode
955 * before glDrawPixels is called and the crash is prevented. There won't
956 * be any interfering gdi accesses, because UnlockRect is called from
957 * ReleaseDC, and the app won't use the dc any more afterwards.
959 if(This->Flags & SFLAG_DIBSECTION) {
961 read = This->resource.allocatedMemory[0];
964 switch (This->resource.format) {
965 /* No special care needed */
966 case WINED3DFMT_A4R4G4B4:
967 case WINED3DFMT_R5G6B5:
968 case WINED3DFMT_A1R5G5B5:
969 case WINED3DFMT_R8G8B8:
970 type = This->glDescription.glType;
971 fmt = This->glDescription.glFormat;
972 mem = This->resource.allocatedMemory;
973 bpp = This->bytesPerPixel;
976 case WINED3DFMT_X4R4G4B4:
979 unsigned short *data;
980 data = (unsigned short *)This->resource.allocatedMemory;
981 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
987 type = This->glDescription.glType;
988 fmt = This->glDescription.glFormat;
989 mem = This->resource.allocatedMemory;
990 bpp = This->bytesPerPixel;
994 case WINED3DFMT_X1R5G5B5:
997 unsigned short *data;
998 data = (unsigned short *)This->resource.allocatedMemory;
999 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
1005 type = This->glDescription.glType;
1006 fmt = This->glDescription.glFormat;
1007 mem = This->resource.allocatedMemory;
1008 bpp = This->bytesPerPixel;
1012 case WINED3DFMT_X8R8G8B8:
1014 /* make sure the X byte is set to alpha on, since it
1015 could be any random value. This fixes the intro movie in Pirates! */
1018 data = (unsigned int *)This->resource.allocatedMemory;
1019 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
1021 *data |= 0xFF000000;
1028 case WINED3DFMT_A8R8G8B8:
1030 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
1031 vcheckGLcall("glPixelStorei");
1032 storechanged = TRUE;
1033 type = This->glDescription.glType;
1034 fmt = This->glDescription.glFormat;
1035 mem = This->resource.allocatedMemory;
1036 bpp = This->bytesPerPixel;
1040 case WINED3DFMT_A2R10G10B10:
1042 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
1043 vcheckGLcall("glPixelStorei");
1044 storechanged = TRUE;
1045 type = This->glDescription.glType;
1046 fmt = This->glDescription.glFormat;
1047 mem = This->resource.allocatedMemory;
1048 bpp = This->bytesPerPixel;
1054 int height = This->glRect.bottom - This->glRect.top;
1055 type = GL_UNSIGNED_BYTE;
1058 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
1060 ERR("Out of memory\n");
1063 memory_allocated = TRUE;
1064 d3dfmt_convert_surface(This->resource.allocatedMemory,
1072 bpp = This->bytesPerPixel * 4;
1078 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
1081 type = This->glDescription.glType;
1082 fmt = This->glDescription.glFormat;
1083 mem = This->resource.allocatedMemory;
1084 bpp = This->bytesPerPixel;
1087 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1088 (This->lockedRect.bottom - This->lockedRect.top)-1,
1090 mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
1091 checkGLcall("glDrawPixels");
1092 glPixelZoom(1.0,1.0);
1093 vcheckGLcall("glPixelZoom");
1095 glRasterPos3iv(&prev_rasterpos[0]);
1096 vcheckGLcall("glRasterPos3iv");
1098 /* Reset to previous pack row length */
1099 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1100 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1102 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
1103 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1106 /* Blitting environment requires that 2D texturing is enabled. It was turned off before,
1109 glEnable(GL_TEXTURE_2D);
1110 checkGLcall("glEnable(GL_TEXTURE_2D)");
1112 if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem);
1116 static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) {
1117 float glTexCoord[4];
1119 glTexCoord[0] = (float) This->lockedRect.left / (float) This->pow2Width; /* left */
1120 glTexCoord[1] = (float) This->lockedRect.right / (float) This->pow2Width; /* right */
1121 glTexCoord[2] = (float) This->lockedRect.top / (float) This->pow2Height; /* top */
1122 glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */
1124 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
1128 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1129 checkGLcall("glEnable glBindTexture");
1131 /* No filtering for blts */
1132 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1133 checkGLcall("glTexParameteri");
1134 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1135 checkGLcall("glTexParameteri");
1137 /* Start drawing a quad */
1140 glColor3d(1.0f, 1.0f, 1.0f);
1141 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1142 glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0);
1144 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1145 glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0);
1147 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1148 glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0);
1150 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1151 glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0);
1154 checkGLcall("glEnd");
1156 /* Unbind the texture */
1157 glBindTexture(GL_TEXTURE_2D, 0);
1158 checkGLcall("glEnable glBindTexture");
1163 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1164 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1165 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1166 IWineD3DSwapChainImpl *swapchain = NULL;
1168 if (!(This->Flags & SFLAG_LOCKED)) {
1169 WARN("trying to Unlock an unlocked surf@%p\n", This);
1170 return WINED3DERR_INVALIDCALL;
1173 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1175 if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
1176 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1180 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1181 if(swapchain || iface == myDevice->render_targets[0]) {
1182 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1183 static BOOL warned = FALSE;
1185 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1188 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1192 /* Activate the correct context for the render target */
1194 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
1197 /* Primary offscreen render target */
1198 TRACE("Offscreen render target\n");
1199 glDrawBuffer(myDevice->offscreenBuffer);
1200 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1202 GLenum buffer = surface_get_gl_buffer(iface, (IWineD3DSwapChain *)swapchain);
1203 TRACE("Unlocking %#x buffer\n", buffer);
1204 glDrawBuffer(buffer);
1205 checkGLcall("glDrawBuffer");
1207 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1210 switch(wined3d_settings.rendertargetlock_mode) {
1214 flush_to_framebuffer_drawpixels(This);
1219 flush_to_framebuffer_texture(This);
1223 glDrawBuffer(myDevice->offscreenBuffer);
1224 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1225 } else if(swapchain->backBuffer) {
1226 glDrawBuffer(GL_BACK);
1227 checkGLcall("glDrawBuffer(GL_BACK)");
1229 glDrawBuffer(GL_FRONT);
1230 checkGLcall("glDrawBuffer(GL_FRONT)");
1234 This->dirtyRect.left = This->currentDesc.Width;
1235 This->dirtyRect.top = This->currentDesc.Height;
1236 This->dirtyRect.right = 0;
1237 This->dirtyRect.bottom = 0;
1238 This->Flags |= SFLAG_INDRAWABLE;
1239 } else if(iface == myDevice->stencilBufferTarget) {
1240 FIXME("Depth Stencil buffer locking is not implemented\n");
1242 /* The rest should be a normal texture */
1243 IWineD3DBaseTextureImpl *impl;
1244 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1245 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1246 * states need resetting
1248 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1249 if(impl->baseTexture.bindCount) {
1250 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1252 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1257 This->Flags &= ~SFLAG_LOCKED;
1258 memset(&This->lockedRect, 0, sizeof(RECT));
1262 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1263 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1264 WINED3DLOCKED_RECT lock;
1271 const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format, NULL, NULL);
1273 TRACE("(%p)->(%p)\n",This,pHDC);
1275 if(This->Flags & SFLAG_USERPTR) {
1276 ERR("Not supported on surfaces with an application-provided surfaces\n");
1277 return WINEDDERR_NODC;
1280 /* Give more detailed info for ddraw */
1281 if (This->Flags & SFLAG_DCINUSE)
1282 return WINEDDERR_DCALREADYCREATED;
1284 /* Can't GetDC if the surface is locked */
1285 if (This->Flags & SFLAG_LOCKED)
1286 return WINED3DERR_INVALIDCALL;
1288 memset(&lock, 0, sizeof(lock)); /* To be sure */
1290 /* Create a DIB section if there isn't a hdc yet */
1293 SYSTEM_INFO sysInfo;
1294 void *oldmem = This->resource.allocatedMemory;
1296 switch (This->bytesPerPixel) {
1299 /* Allocate extra space to store the RGB bit masks. */
1300 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1304 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1308 /* Allocate extra space for a palette. */
1309 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1310 sizeof(BITMAPINFOHEADER)
1312 * (1 << (This->bytesPerPixel * 8)));
1317 return E_OUTOFMEMORY;
1319 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1320 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1321 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1322 * add an extra line to the dib section
1324 GetSystemInfo(&sysInfo);
1325 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1327 TRACE("Adding an extra line to the dib section\n");
1330 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1331 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
1332 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / This->bytesPerPixel;
1333 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1334 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1335 b_info->bmiHeader.biPlanes = 1;
1336 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1338 b_info->bmiHeader.biXPelsPerMeter = 0;
1339 b_info->bmiHeader.biYPelsPerMeter = 0;
1340 b_info->bmiHeader.biClrUsed = 0;
1341 b_info->bmiHeader.biClrImportant = 0;
1343 /* Get the bit masks */
1344 masks = (DWORD *) &(b_info->bmiColors);
1345 switch (This->resource.format) {
1346 case WINED3DFMT_R8G8B8:
1347 usage = DIB_RGB_COLORS;
1348 b_info->bmiHeader.biCompression = BI_RGB;
1351 case WINED3DFMT_X1R5G5B5:
1352 case WINED3DFMT_A1R5G5B5:
1353 case WINED3DFMT_A4R4G4B4:
1354 case WINED3DFMT_X4R4G4B4:
1355 case WINED3DFMT_R3G3B2:
1356 case WINED3DFMT_A8R3G3B2:
1357 case WINED3DFMT_A2B10G10R10:
1358 case WINED3DFMT_A8B8G8R8:
1359 case WINED3DFMT_X8B8G8R8:
1360 case WINED3DFMT_A2R10G10B10:
1361 case WINED3DFMT_R5G6B5:
1362 case WINED3DFMT_A16B16G16R16:
1364 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1365 masks[0] = formatEntry->redMask;
1366 masks[1] = formatEntry->greenMask;
1367 masks[2] = formatEntry->blueMask;
1371 /* Don't know palette */
1372 b_info->bmiHeader.biCompression = BI_RGB;
1379 HeapFree(GetProcessHeap(), 0, b_info);
1380 return HRESULT_FROM_WIN32(GetLastError());
1383 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);
1384 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1387 if (!This->dib.DIBsection) {
1388 ERR("CreateDIBSection failed!\n");
1389 HeapFree(GetProcessHeap(), 0, b_info);
1390 return HRESULT_FROM_WIN32(GetLastError());
1393 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1395 /* copy the existing surface to the dib section */
1396 if(This->resource.allocatedMemory) {
1397 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1398 /* We won't need that any more */
1400 /* This is to make LockRect read the gl Texture although memory is allocated */
1401 This->Flags &= ~SFLAG_INSYSMEM;
1404 HeapFree(GetProcessHeap(), 0, b_info);
1406 /* Use the dib section from now on */
1407 This->resource.allocatedMemory = This->dib.bitmap_data;
1409 /* Now allocate a HDC */
1410 This->hDC = CreateCompatibleDC(0);
1411 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1412 TRACE("using wined3d palette %p\n", This->palette);
1413 SelectPalette(This->hDC,
1414 This->palette ? This->palette->hpal : 0,
1417 This->Flags |= SFLAG_DIBSECTION;
1419 if(This->Flags & SFLAG_CLIENT) {
1420 IWineD3DSurface_PreLoad(iface);
1422 HeapFree(GetProcessHeap(), 0, oldmem);
1425 /* Lock the surface */
1426 hr = IWineD3DSurface_LockRect(iface,
1431 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1432 /* keep the dib section */
1436 if(This->resource.format == WINED3DFMT_P8 ||
1437 This->resource.format == WINED3DFMT_A8P8) {
1440 PALETTEENTRY ent[256];
1442 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1443 for (n=0; n<256; n++) {
1444 col[n].rgbRed = ent[n].peRed;
1445 col[n].rgbGreen = ent[n].peGreen;
1446 col[n].rgbBlue = ent[n].peBlue;
1447 col[n].rgbReserved = 0;
1450 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1452 for (n=0; n<256; n++) {
1453 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1454 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1455 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1456 col[n].rgbReserved = 0;
1460 SetDIBColorTable(This->hDC, 0, 256, col);
1464 TRACE("returning %p\n",*pHDC);
1465 This->Flags |= SFLAG_DCINUSE;
1470 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1471 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1473 TRACE("(%p)->(%p)\n",This,hDC);
1475 if (!(This->Flags & SFLAG_DCINUSE))
1476 return WINED3DERR_INVALIDCALL;
1478 /* we locked first, so unlock now */
1479 IWineD3DSurface_UnlockRect(iface);
1481 This->Flags &= ~SFLAG_DCINUSE;
1486 /* ******************************************************
1487 IWineD3DSurface Internal (No mapping to directx api) parts follow
1488 ****************************************************** */
1490 static 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, BOOL srgb_mode) {
1491 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
1492 const GlPixelFormatDesc *glDesc;
1493 getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc);
1495 /* Default values: From the surface */
1496 *format = glDesc->glFormat;
1497 *internal = srgb_mode?glDesc->glGammaInternal:glDesc->glInternal;
1498 *type = glDesc->glType;
1499 *convert = NO_CONVERSION;
1500 *target_bpp = This->bytesPerPixel;
1502 /* Ok, now look if we have to do any conversion */
1503 switch(This->resource.format) {
1508 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1509 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1511 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1513 *internal = GL_RGBA;
1514 *type = GL_UNSIGNED_BYTE;
1516 if(colorkey_active) {
1517 *convert = CONVERT_PALETTED_CK;
1519 *convert = CONVERT_PALETTED;
1525 case WINED3DFMT_R3G3B2:
1526 /* **********************
1527 GL_UNSIGNED_BYTE_3_3_2
1528 ********************** */
1529 if (colorkey_active) {
1530 /* This texture format will never be used.. So do not care about color keying
1531 up until the point in time it will be needed :-) */
1532 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1536 case WINED3DFMT_R5G6B5:
1537 if (colorkey_active) {
1538 *convert = CONVERT_CK_565;
1540 *internal = GL_RGBA;
1541 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1545 case WINED3DFMT_X1R5G5B5:
1546 if (colorkey_active) {
1547 *convert = CONVERT_CK_5551;
1549 *internal = GL_RGBA;
1550 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
1554 case WINED3DFMT_R8G8B8:
1555 if (colorkey_active) {
1556 *convert = CONVERT_CK_RGB24;
1558 *internal = GL_RGBA;
1559 *type = GL_UNSIGNED_INT_8_8_8_8;
1564 case WINED3DFMT_X8R8G8B8:
1565 if (colorkey_active) {
1566 *convert = CONVERT_RGB32_888;
1568 *internal = GL_RGBA;
1569 *type = GL_UNSIGNED_INT_8_8_8_8;
1573 case WINED3DFMT_V8U8:
1574 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1575 else if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) {
1576 *format = GL_DUDV_ATI;
1577 *internal = GL_DU8DV8_ATI;
1579 /* No conversion - Just change the gl type */
1582 *convert = CONVERT_V8U8;
1584 *internal = GL_RGB8;
1585 *type = GL_UNSIGNED_BYTE;
1589 case WINED3DFMT_X8L8V8U8:
1590 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1591 *convert = CONVERT_X8L8V8U8;
1593 *internal = GL_RGBA8;
1594 *type = GL_UNSIGNED_BYTE;
1596 /* Not supported by GL_ATI_envmap_bumpmap */
1599 case WINED3DFMT_Q8W8V8U8:
1600 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1601 *convert = CONVERT_Q8W8V8U8;
1603 *internal = GL_RGBA8;
1604 *type = GL_UNSIGNED_BYTE;
1606 /* Not supported by GL_ATI_envmap_bumpmap */
1609 case WINED3DFMT_V16U16:
1610 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1611 *convert = CONVERT_V16U16;
1613 *internal = GL_RGB16;
1616 /* What should I do here about GL_ATI_envmap_bumpmap?
1617 * Convert it or allow data loss by loading it into a 8 bit / channel texture?
1628 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1629 BYTE *source, *dest;
1630 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1635 memcpy(dst, src, pitch * height);
1638 case CONVERT_PALETTED:
1639 case CONVERT_PALETTED_CK:
1641 IWineD3DPaletteImpl* pal = surf->palette;
1647 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1651 /* Still no palette? Use the device's palette */
1652 /* Get the surface's palette */
1653 for (i = 0; i < 256; i++) {
1654 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1656 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1657 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1658 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1659 if ((convert == CONVERT_PALETTED_CK) &&
1660 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1661 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1662 /* We should maybe here put a more 'neutral' color than the standard bright purple
1663 one often used by application to prevent the nice purple borders when bi-linear
1671 TRACE("Using surface palette %p\n", pal);
1672 /* Get the surface's palette */
1673 for (i = 0; i < 256; i++) {
1674 table[i][0] = pal->palents[i].peRed;
1675 table[i][1] = pal->palents[i].peGreen;
1676 table[i][2] = pal->palents[i].peBlue;
1677 if ((convert == CONVERT_PALETTED_CK) &&
1678 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1679 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1680 /* We should maybe here put a more 'neutral' color than the standard bright purple
1681 one often used by application to prevent the nice purple borders when bi-linear
1684 } else if(pal->Flags & WINEDDPCAPS_ALPHA) {
1685 table[i][3] = pal->palents[i].peFlags;
1692 for (y = 0; y < height; y++)
1694 source = src + pitch * y;
1695 dest = dst + outpitch * y;
1696 /* This is an 1 bpp format, using the width here is fine */
1697 for (x = 0; x < width; x++) {
1698 BYTE color = *source++;
1699 *dest++ = table[color][0];
1700 *dest++ = table[color][1];
1701 *dest++ = table[color][2];
1702 *dest++ = table[color][3];
1708 case CONVERT_CK_565:
1710 /* Converting the 565 format in 5551 packed to emulate color-keying.
1712 Note : in all these conversion, it would be best to average the averaging
1713 pixels to get the color of the pixel that will be color-keyed to
1714 prevent 'color bleeding'. This will be done later on if ever it is
1717 Note2: Nvidia documents say that their driver does not support alpha + color keying
1718 on the same surface and disables color keying in such a case
1724 TRACE("Color keyed 565\n");
1726 for (y = 0; y < height; y++) {
1727 Source = (WORD *) (src + y * pitch);
1728 Dest = (WORD *) (dst + y * outpitch);
1729 for (x = 0; x < width; x++ ) {
1730 WORD color = *Source++;
1731 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1732 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1733 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1742 case CONVERT_CK_5551:
1744 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
1748 TRACE("Color keyed 5551\n");
1749 for (y = 0; y < height; y++) {
1750 Source = (WORD *) (src + y * pitch);
1751 Dest = (WORD *) (dst + y * outpitch);
1752 for (x = 0; x < width; x++ ) {
1753 WORD color = *Source++;
1755 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1756 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1760 *Dest &= ~(1 << 15);
1772 unsigned char *Dest;
1773 for(y = 0; y < height; y++) {
1774 Source = (short *) (src + y * pitch);
1775 Dest = (unsigned char *) (dst + y * outpitch);
1776 for (x = 0; x < width; x++ ) {
1777 long color = (*Source++);
1778 /* B */ Dest[0] = 0xff;
1779 /* G */ Dest[1] = (color >> 8) + 128; /* V */
1780 /* R */ Dest[2] = (color) + 128; /* U */
1787 case CONVERT_Q8W8V8U8:
1791 unsigned char *Dest;
1792 for(y = 0; y < height; y++) {
1793 Source = (DWORD *) (src + y * pitch);
1794 Dest = (unsigned char *) (dst + y * outpitch);
1795 for (x = 0; x < width; x++ ) {
1796 long color = (*Source++);
1797 /* B */ Dest[0] = ((color >> 16) & 0xff) + 128; /* W */
1798 /* G */ Dest[1] = ((color >> 8 ) & 0xff) + 128; /* V */
1799 /* R */ Dest[2] = (color & 0xff) + 128; /* U */
1800 /* A */ Dest[3] = ((color >> 24) & 0xff) + 128; /* Q */
1808 ERR("Unsupported conversation type %d\n", convert);
1813 /* This function is used in case of 8bit paletted textures to upload the palette.
1814 For now it only supports GL_EXT_paletted_texture extension but support for other
1815 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1817 static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1818 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1819 IWineD3DPaletteImpl* pal = This->palette;
1824 /* Still no palette? Use the device's palette */
1825 /* Get the surface's palette */
1826 for (i = 0; i < 256; i++) {
1827 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1829 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1830 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1831 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1832 if ((convert == CONVERT_PALETTED_CK) &&
1833 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1834 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1835 /* We should maybe here put a more 'neutral' color than the standard bright purple
1836 one often used by application to prevent the nice purple borders when bi-linear
1844 TRACE("Using surface palette %p\n", pal);
1845 /* Get the surface's palette */
1846 for (i = 0; i < 256; i++) {
1847 table[i][0] = pal->palents[i].peRed;
1848 table[i][1] = pal->palents[i].peGreen;
1849 table[i][2] = pal->palents[i].peBlue;
1850 if ((convert == CONVERT_PALETTED_CK) &&
1851 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1852 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1853 /* We should maybe here put a more 'neutral' color than the standard bright purple
1854 one often used by application to prevent the nice purple borders when bi-linear
1857 } else if(pal->Flags & WINEDDPCAPS_ALPHA) {
1858 table[i][3] = pal->palents[i].peFlags;
1864 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1867 static BOOL palette9_changed(IWineD3DSurfaceImpl *This) {
1868 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1870 if(This->palette || (This->resource.format != WINED3DFMT_P8 && This->resource.format != WINED3DFMT_A8P8)) {
1871 /* If a ddraw-style palette is attached assume no d3d9 palette change.
1872 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
1877 if(This->palette9) {
1878 if(memcmp(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256) == 0) {
1882 This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1884 memcpy(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
1888 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) {
1889 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1890 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1891 GLenum format, internal, type;
1892 CONVERT_TYPES convert;
1894 int width, pitch, outpitch;
1897 if (!(This->Flags & SFLAG_INTEXTURE)) {
1898 TRACE("Reloading because surface is dirty\n");
1899 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1900 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) ||
1901 /* Reload: vice versa OR */
1902 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & WINEDDSD_CKSRCBLT)) ||
1903 /* Also reload: Color key is active AND the color key has changed */
1904 ((This->CKeyFlags & WINEDDSD_CKSRCBLT) && (
1905 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1906 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1907 TRACE("Reloading because of color keying\n");
1908 } else if(palette9_changed(This)) {
1909 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
1911 TRACE("surface is already in texture\n");
1915 This->Flags |= SFLAG_INTEXTURE;
1917 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1918 * These resources are not bound by device size or format restrictions. Because of this,
1919 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1920 * However, these resources can always be created, locked, and copied.
1922 if (This->resource.pool == WINED3DPOOL_SCRATCH )
1924 FIXME("(%p) Operation not supported for scratch textures\n",This);
1925 return WINED3DERR_INVALIDCALL;
1928 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, srgb_mode);
1930 if (This->Flags & SFLAG_INDRAWABLE) {
1931 if (This->glDescription.level != 0)
1932 FIXME("Surface in texture is only supported for level 0\n");
1933 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1934 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1935 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1936 This->resource.format == WINED3DFMT_DXT5)
1937 FIXME("Format %d not supported\n", This->resource.format);
1942 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1943 vcheckGLcall("glGetIntegerv");
1944 glReadBuffer(This->resource.wineD3DDevice->offscreenBuffer);
1945 vcheckGLcall("glReadBuffer");
1947 if(!(This->Flags & SFLAG_ALLOCATED)) {
1948 surface_allocate_surface(This, internal, This->pow2Width,
1949 This->pow2Height, format, type);
1952 glCopyTexSubImage2D(This->glDescription.target,
1953 This->glDescription.level,
1955 This->currentDesc.Width,
1956 This->currentDesc.Height);
1957 checkGLcall("glCopyTexSubImage2D");
1959 glReadBuffer(prevRead);
1960 vcheckGLcall("glReadBuffer");
1964 TRACE("Updated target %d\n", This->glDescription.target);
1968 /* The only place where LoadTexture() might get called when isInDraw=1
1969 * is ActivateContext where lastActiveRenderTarget is preloaded.
1971 if(iface == device->lastActiveRenderTarget && device->isInDraw)
1972 ERR("Reading back render target but SFLAG_INDRAWABLE not set\n");
1974 /* Otherwise: System memory copy must be most up to date */
1976 if(This->CKeyFlags & WINEDDSD_CKSRCBLT) {
1977 This->Flags |= SFLAG_GLCKEY;
1978 This->glCKey = This->SrcBltCKey;
1980 else This->Flags &= ~SFLAG_GLCKEY;
1982 /* The width is in 'length' not in bytes */
1983 width = This->currentDesc.Width;
1984 pitch = IWineD3DSurface_GetPitch(iface);
1986 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1987 int height = This->currentDesc.Height;
1989 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1990 outpitch = width * bpp;
1991 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
1993 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1995 ERR("Out of memory %d, %d!\n", outpitch, height);
1996 return WINED3DERR_OUTOFVIDEOMEMORY;
1998 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
2000 This->Flags |= SFLAG_CONVERTED;
2001 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
2002 d3dfmt_p8_upload_palette(iface, convert);
2003 This->Flags &= ~SFLAG_CONVERTED;
2004 mem = This->resource.allocatedMemory;
2006 This->Flags &= ~SFLAG_CONVERTED;
2007 mem = This->resource.allocatedMemory;
2010 /* Make sure the correct pitch is used */
2011 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
2013 if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
2014 TRACE("non power of two support\n");
2015 if(!(This->Flags & SFLAG_ALLOCATED)) {
2016 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
2019 surface_upload_data(This, internal, This->currentDesc.Width, This->currentDesc.Height, format, type, mem);
2022 /* When making the realloc conditional, keep in mind that GL_APPLE_client_storage may be in use, and This->resource.allocatedMemory
2023 * changed. So also keep track of memory changes. In this case the texture has to be reallocated
2025 if(!(This->Flags & SFLAG_ALLOCATED)) {
2026 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
2029 surface_upload_data(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
2033 /* Restore the default pitch */
2034 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2036 if (mem != This->resource.allocatedMemory)
2037 HeapFree(GetProcessHeap(), 0, mem);
2041 static unsigned int gen = 0;
2044 if ((gen % 10) == 0) {
2045 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
2046 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
2049 * debugging crash code
2058 if (!(This->Flags & SFLAG_DONOTFREE)) {
2059 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2060 This->resource.allocatedMemory = NULL;
2061 This->Flags &= ~SFLAG_INSYSMEM;
2069 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
2072 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2073 char *allocatedMemory;
2075 IWineD3DSwapChain *swapChain = NULL;
2077 GLuint tmpTexture = 0;
2080 Textures may not be stored in ->allocatedgMemory and a GlTexture
2081 so we should lock the surface before saving a snapshot, or at least check that
2083 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
2084 by calling GetTexImage and in compressed form by calling
2085 GetCompressedTexImageARB. Queried compressed images can be saved and
2086 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
2087 texture images do not need to be processed by the GL and should
2088 significantly improve texture loading performance relative to uncompressed
2091 /* Setup the width and height to be the internal texture width and height. */
2092 width = This->pow2Width;
2093 height = This->pow2Height;
2094 /* check to see if we're a 'virtual' texture, e.g. we're not a pbuffer of texture, we're a back buffer*/
2095 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
2097 if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) {
2098 /* if were not a real texture then read the back buffer into a real texture */
2099 /* we don't want to interfere with the back buffer so read the data into a temporary
2100 * texture and then save the data out of the temporary texture
2104 TRACE("(%p) Reading render target into texture\n", This);
2105 glEnable(GL_TEXTURE_2D);
2107 glGenTextures(1, &tmpTexture);
2108 glBindTexture(GL_TEXTURE_2D, tmpTexture);
2110 glTexImage2D(GL_TEXTURE_2D,
2117 GL_UNSIGNED_INT_8_8_8_8_REV,
2120 glGetIntegerv(GL_READ_BUFFER, &prevRead);
2121 vcheckGLcall("glGetIntegerv");
2122 glReadBuffer(swapChain ? GL_BACK : This->resource.wineD3DDevice->offscreenBuffer);
2123 vcheckGLcall("glReadBuffer");
2124 glCopyTexImage2D(GL_TEXTURE_2D,
2133 checkGLcall("glCopyTexImage2D");
2134 glReadBuffer(prevRead);
2137 } else { /* bind the real texture, and make sure it up to date */
2138 IWineD3DSurface_PreLoad(iface);
2140 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
2142 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
2143 glGetTexImage(GL_TEXTURE_2D,
2144 This->glDescription.level,
2146 GL_UNSIGNED_INT_8_8_8_8_REV,
2148 checkGLcall("glTexImage2D");
2150 glBindTexture(GL_TEXTURE_2D, 0);
2151 glDeleteTextures(1, &tmpTexture);
2155 f = fopen(filename, "w+");
2157 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2158 return WINED3DERR_INVALIDCALL;
2160 /* Save the data out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha channel */
2161 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2176 fwrite(&width,2,1,f);
2178 fwrite(&height,2,1,f);
2183 /* 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 */
2185 textureRow = allocatedMemory + (width * (height - 1) *4);
2187 textureRow = allocatedMemory;
2188 for (y = 0 ; y < height; y++) {
2189 for (i = 0; i < width; i++) {
2190 color = *((DWORD*)textureRow);
2191 fputc((color >> 16) & 0xFF, f); /* B */
2192 fputc((color >> 8) & 0xFF, f); /* G */
2193 fputc((color >> 0) & 0xFF, f); /* R */
2194 fputc((color >> 24) & 0xFF, f); /* A */
2197 /* take two rows of the pointer to the texture memory */
2199 (textureRow-= width << 3);
2202 TRACE("Closing file\n");
2206 IWineD3DSwapChain_Release(swapChain);
2208 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2213 * Slightly inefficient way to handle multiple dirty rects but it works :)
2215 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2216 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2217 IWineD3DBaseTexture *baseTexture = NULL;
2218 if (!(This->Flags & SFLAG_INSYSMEM) && (This->Flags & SFLAG_INTEXTURE))
2219 surface_download_data(This);
2221 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
2222 if (NULL != pDirtyRect) {
2223 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2224 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2225 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2226 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2228 This->dirtyRect.left = 0;
2229 This->dirtyRect.top = 0;
2230 This->dirtyRect.right = This->currentDesc.Width;
2231 This->dirtyRect.bottom = This->currentDesc.Height;
2233 TRACE("(%p) : Dirty: yes, Rect:(%d,%d,%d,%d)\n", This, This->dirtyRect.left,
2234 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2235 /* if the container is a basetexture then mark it dirty. */
2236 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2237 TRACE("Passing to container\n");
2238 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2239 IWineD3DBaseTexture_Release(baseTexture);
2244 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2245 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2247 TRACE("This %p, container %p\n", This, container);
2249 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2251 TRACE("Setting container to %p from %p\n", container, This->container);
2252 This->container = container;
2257 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2258 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2259 const GlPixelFormatDesc *glDesc;
2260 const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(format, &GLINFO_LOCATION, &glDesc);
2262 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2263 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2264 return WINED3DERR_INVALIDCALL;
2267 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
2268 if (format == WINED3DFMT_UNKNOWN) {
2269 This->resource.size = 0;
2270 } else if (format == WINED3DFMT_DXT1) {
2271 /* DXT1 is half byte per pixel */
2272 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2274 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2275 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2276 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2278 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
2279 This->resource.size = ((This->pow2Width * formatEntry->bpp) + alignment - 1) & ~(alignment - 1);
2280 This->resource.size *= This->pow2Height;
2284 /* Setup some glformat defaults */
2285 This->glDescription.glFormat = glDesc->glFormat;
2286 This->glDescription.glFormatInternal = glDesc->glInternal;
2287 This->glDescription.glType = glDesc->glType;
2289 if (format != WINED3DFMT_UNKNOWN) {
2290 This->bytesPerPixel = formatEntry->bpp;
2292 This->bytesPerPixel = 0;
2295 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2296 This->Flags &= ~SFLAG_ALLOCATED;
2298 This->resource.format = format;
2300 TRACE("(%p) : Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
2305 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2306 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2308 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer */
2309 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2310 ERR("Not supported on render targets\n");
2311 return WINED3DERR_INVALIDCALL;
2314 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2315 WARN("Surface is locked or the HDC is in use\n");
2316 return WINED3DERR_INVALIDCALL;
2319 if(Mem && Mem != This->resource.allocatedMemory) {
2320 void *release = NULL;
2322 /* Do I have to copy the old surface content? */
2323 if(This->Flags & SFLAG_DIBSECTION) {
2324 /* Release the DC. No need to hold the critical section for the update
2325 * Thread because this thread runs only on front buffers, but this method
2326 * fails for render targets in the check above.
2328 SelectObject(This->hDC, This->dib.holdbitmap);
2329 DeleteDC(This->hDC);
2330 /* Release the DIB section */
2331 DeleteObject(This->dib.DIBsection);
2332 This->dib.bitmap_data = NULL;
2333 This->resource.allocatedMemory = NULL;
2335 This->Flags &= ~SFLAG_DIBSECTION;
2336 } else if(!(This->Flags & SFLAG_USERPTR)) {
2337 release = This->resource.allocatedMemory;
2339 This->resource.allocatedMemory = Mem;
2340 This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
2342 /* Now the surface memory is most up do date. Invalidate drawable and texture */
2343 This->Flags &= ~(SFLAG_INDRAWABLE | SFLAG_INTEXTURE);
2345 /* For client textures opengl has to be notified */
2346 if(This->Flags & SFLAG_CLIENT) {
2347 This->Flags &= ~SFLAG_ALLOCATED;
2348 IWineD3DSurface_PreLoad(iface);
2349 /* And hope that the app behaves correctly and did not free the old surface memory before setting a new pointer */
2352 /* Now free the old memory if any */
2353 HeapFree(GetProcessHeap(), 0, release);
2354 } else if(This->Flags & SFLAG_USERPTR) {
2355 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2356 This->resource.allocatedMemory = NULL;
2357 This->Flags &= ~SFLAG_USERPTR;
2359 if(This->Flags & SFLAG_CLIENT) {
2360 This->Flags &= ~SFLAG_ALLOCATED;
2361 /* This respecifies an empty texture and opengl knows that the old memory is gone */
2362 IWineD3DSurface_PreLoad(iface);
2368 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2369 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2370 IWineD3DSwapChainImpl *swapchain = NULL;
2372 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2374 /* Flipping is only supported on RenderTargets */
2375 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return WINEDDERR_NOTFLIPPABLE;
2378 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2379 * FIXME("(%p) Target override is not supported by now\n", This);
2380 * Additionally, it isn't really possible to support triple-buffering
2381 * properly on opengl at all
2385 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain);
2387 ERR("Flipped surface is not on a swapchain\n");
2388 return WINEDDERR_NOTFLIPPABLE;
2391 /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
2392 * and only d3d8 and d3d9 apps specify the presentation interval
2394 if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) {
2395 /* Most common case first to avoid wasting time on all the other cases */
2396 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
2397 } else if(Flags & WINEDDFLIP_NOVSYNC) {
2398 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
2399 } else if(Flags & WINEDDFLIP_INTERVAL2) {
2400 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
2401 } else if(Flags & WINEDDFLIP_INTERVAL3) {
2402 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
2404 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
2407 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2408 hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *) swapchain, NULL, NULL, 0, NULL, 0);
2409 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2413 /* Does a direct frame buffer -> texture copy. Stretching is done
2414 * with single pixel copy calls
2416 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter) {
2417 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2420 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2424 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2425 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2427 /* Bind the target texture */
2428 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2429 checkGLcall("glBindTexture");
2431 glReadBuffer(myDevice->offscreenBuffer);
2433 GLenum buffer = surface_get_gl_buffer(SrcSurface, (IWineD3DSwapChain *)swapchain);
2434 glReadBuffer(buffer);
2436 checkGLcall("glReadBuffer");
2438 xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
2439 yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
2441 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2442 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2444 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
2445 ERR("Texture filtering not supported in direct blit\n");
2447 } else if((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) && ((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2448 ERR("Texture filtering not supported in direct blit\n");
2452 !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) &&
2453 !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2454 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2456 glCopyTexSubImage2D(This->glDescription.target,
2457 This->glDescription.level,
2458 drect->x1, drect->y1, /* xoffset, yoffset */
2459 srect->x1, Src->currentDesc.Height - srect->y2,
2460 drect->x2 - drect->x1, drect->y2 - drect->y1);
2462 UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
2463 /* I have to process this row by row to swap the image,
2464 * otherwise it would be upside down, so stretching in y direction
2465 * doesn't cost extra time
2467 * However, stretching in x direction can be avoided if not necessary
2469 for(row = drect->y1; row < drect->y2; row++) {
2470 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2471 /* Well, that stuff works, but it's very slow.
2472 * find a better way instead
2476 for(col = drect->x1; col < drect->x2; col++) {
2477 glCopyTexSubImage2D(This->glDescription.target,
2478 This->glDescription.level,
2479 drect->x1 + col, row, /* xoffset, yoffset */
2480 srect->x1 + col * xrel, yoffset - (int) (row * yrel),
2484 glCopyTexSubImage2D(This->glDescription.target,
2485 This->glDescription.level,
2486 drect->x1, row, /* xoffset, yoffset */
2487 srect->x1, yoffset - (int) (row * yrel),
2488 drect->x2-drect->x1, 1);
2493 vcheckGLcall("glCopyTexSubImage2D");
2497 /* Uses the hardware to stretch and flip the image */
2498 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter) {
2499 GLuint src, backup = 0;
2500 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2501 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2502 float left, right, top, bottom; /* Texture coordinates */
2503 UINT fbwidth = Src->currentDesc.Width;
2504 UINT fbheight = Src->currentDesc.Height;
2505 GLenum drawBuffer = GL_BACK;
2507 TRACE("Using hwstretch blit\n");
2508 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2510 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2511 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2513 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2514 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2516 if(GL_LIMITS(aux_buffers) >= 2) {
2517 /* Got more than one aux buffer? Use the 2nd aux buffer */
2518 drawBuffer = GL_AUX1;
2519 } else if((swapchain || myDevice->offscreenBuffer == GL_BACK) && GL_LIMITS(aux_buffers) >= 1) {
2520 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2521 drawBuffer = GL_AUX0;
2524 if(!swapchain && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2525 glGenTextures(1, &backup);
2526 checkGLcall("glGenTextures\n");
2527 glBindTexture(GL_TEXTURE_2D, backup);
2528 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2530 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2531 * we are reading from the back buffer, the backup can be used as source texture
2533 if(Src->glDescription.textureName == 0) {
2534 /* Get it a description */
2535 IWineD3DSurface_PreLoad(SrcSurface);
2537 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2538 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2540 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2541 Src->Flags &= ~SFLAG_INTEXTURE;
2544 glReadBuffer(GL_BACK);
2545 checkGLcall("glReadBuffer(GL_BACK)");
2547 /* TODO: Only back up the part that will be overwritten */
2548 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2549 0, 0 /* read offsets */,
2554 checkGLcall("glCopyTexSubImage2D");
2556 /* No issue with overriding these - the sampler is dirty due to blit usage */
2557 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2558 stateLookup[WINELOOKUP_MAGFILTER][Filter - minLookup[WINELOOKUP_MAGFILTER]]);
2559 checkGLcall("glTexParameteri");
2560 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2561 minMipLookup[Filter][WINED3DTEXF_NONE]);
2562 checkGLcall("glTexParameteri");
2564 if(!swapchain || (IWineD3DSurface *) Src == swapchain->backBuffer[0]) {
2565 src = backup ? backup : Src->glDescription.textureName;
2567 glReadBuffer(GL_FRONT);
2568 checkGLcall("glReadBuffer(GL_FRONT)");
2570 glGenTextures(1, &src);
2571 checkGLcall("glGenTextures(1, &src)");
2572 glBindTexture(GL_TEXTURE_2D, src);
2573 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2575 /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2576 * out for power of 2 sizes
2578 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2579 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2580 checkGLcall("glTexImage2D");
2581 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2582 0, 0 /* read offsets */,
2587 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2588 checkGLcall("glTexParameteri");
2589 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2590 checkGLcall("glTexParameteri");
2592 glReadBuffer(GL_BACK);
2593 checkGLcall("glReadBuffer(GL_BACK)");
2595 checkGLcall("glEnd and previous");
2597 left = (float) srect->x1 / (float) Src->pow2Width;
2598 right = (float) srect->x2 / (float) Src->pow2Width;
2601 top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2602 bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2604 top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2605 bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2608 /* draw the source texture stretched and upside down. The correct surface is bound already */
2609 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2610 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2612 glDrawBuffer(drawBuffer);
2613 glReadBuffer(drawBuffer);
2617 glTexCoord2f(left, bottom);
2618 glVertex2i(0, fbheight);
2621 glTexCoord2f(left, top);
2622 glVertex2i(0, fbheight - drect->y2 - drect->y1);
2625 glTexCoord2f(right, top);
2626 glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
2629 glTexCoord2f(right, bottom);
2630 glVertex2i(drect->x2 - drect->x1, fbheight);
2632 checkGLcall("glEnd and previous");
2634 /* Now read the stretched and upside down image into the destination texture */
2635 glBindTexture(This->glDescription.target, This->glDescription.textureName);
2636 checkGLcall("glBindTexture");
2637 glCopyTexSubImage2D(This->glDescription.target,
2639 drect->x1, drect->y1, /* xoffset, yoffset */
2640 0, 0, /* We blitted the image to the origin */
2641 drect->x2 - drect->x1, drect->y2 - drect->y1);
2642 checkGLcall("glCopyTexSubImage2D");
2644 /* Write the back buffer backup back */
2645 glBindTexture(GL_TEXTURE_2D, backup ? backup : Src->glDescription.textureName);
2646 checkGLcall("glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName)");
2648 if(drawBuffer == GL_BACK) {
2651 glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height);
2655 glTexCoord2f(0.0, 0.0);
2656 glVertex2i(0, fbheight);
2659 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0);
2660 glVertex2i(fbwidth, Src->currentDesc.Height);
2663 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
2664 glVertex2i(fbwidth, 0);
2667 /* Restore the old draw buffer */
2668 glDrawBuffer(GL_BACK);
2672 if(src != Src->glDescription.textureName && src != backup) {
2673 glDeleteTextures(1, &src);
2674 checkGLcall("glDeleteTextures(1, &src)");
2677 glDeleteTextures(1, &backup);
2678 checkGLcall("glDeleteTextures(1, &backup)");
2683 /* Not called from the VTable */
2684 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
2686 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2687 IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
2688 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2690 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2692 /* Get the swapchain. One of the surfaces has to be a primary surface */
2693 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
2694 if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
2696 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
2697 if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
2700 /* Early sort out of cases where no render target is used */
2701 if(!dstSwapchain && !srcSwapchain &&
2702 SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2703 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
2704 return WINED3DERR_INVALIDCALL;
2707 /* No destination color keying supported */
2708 if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) {
2709 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2710 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2711 return WINED3DERR_INVALIDCALL;
2715 rect.x1 = DestRect->left;
2716 rect.y1 = DestRect->top;
2717 rect.x2 = DestRect->right;
2718 rect.y2 = DestRect->bottom;
2722 rect.x2 = This->currentDesc.Width;
2723 rect.y2 = This->currentDesc.Height;
2726 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
2727 if(dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->backBuffer &&
2728 ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) && SrcSurface == dstSwapchain->backBuffer[0]) {
2729 /* Half-life does a Blt from the back buffer to the front buffer,
2730 * Full surface size, no flags... Use present instead
2732 * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
2735 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2739 TRACE("Looking if a Present can be done...\n");
2740 /* Source Rectangle must be full surface */
2742 if(SrcRect->left != 0 || SrcRect->top != 0 ||
2743 SrcRect->right != Src->currentDesc.Width || SrcRect->bottom != Src->currentDesc.Height) {
2744 TRACE("No, Source rectangle doesn't match\n");
2750 mySrcRect.right = Src->currentDesc.Width;
2751 mySrcRect.bottom = Src->currentDesc.Height;
2753 /* No stretching may occur */
2754 if(mySrcRect.right != rect.x2 - rect.x1 ||
2755 mySrcRect.bottom != rect.y2 - rect.y1) {
2756 TRACE("No, stretching is done\n");
2760 /* Destination must be full surface or match the clipping rectangle */
2761 if(This->clipper && ((IWineD3DClipperImpl *) This->clipper)->hWnd)
2765 GetClientRect(((IWineD3DClipperImpl *) This->clipper)->hWnd, &cliprect);
2770 MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl *) This->clipper)->hWnd,
2773 if(pos[0].x != cliprect.left || pos[0].y != cliprect.top ||
2774 pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
2776 TRACE("No, dest rectangle doesn't match(clipper)\n");
2777 TRACE("Clip rect at (%d,%d)-(%d,%d)\n", cliprect.left, cliprect.top, cliprect.right, cliprect.bottom);
2778 TRACE("Blt dest: (%d,%d)-(%d,%d)\n", rect.x1, rect.y1, rect.x2, rect.y2);
2784 if(rect.x1 != 0 || rect.y1 != 0 ||
2785 rect.x2 != This->currentDesc.Width || rect.y2 != This->currentDesc.Height) {
2786 TRACE("No, dest rectangle doesn't match(surface size)\n");
2793 /* These flags are unimportant for the flag check, remove them */
2794 if((Flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)) == 0) {
2795 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
2797 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2798 * take very long, while a flip is fast.
2799 * This applies to Half-Life, which does such Blts every time it finished
2800 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2801 * menu. This is also used by all apps when they do windowed rendering
2803 * The problem is that flipping is not really the same as copying. After a
2804 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2805 * untouched. Therefore it's necessary to override the swap effect
2806 * and to set it back after the flip.
2808 * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
2812 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2813 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
2815 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2816 IWineD3DSwapChain_Present((IWineD3DSwapChain *) dstSwapchain, NULL, NULL, 0, NULL, 0);
2818 dstSwapchain->presentParms.SwapEffect = orig_swap;
2825 TRACE("Unsupported blit between buffers on the same swapchain\n");
2826 return WINED3DERR_INVALIDCALL;
2827 } else if((dstSwapchain || This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) &&
2828 (srcSwapchain || SrcSurface == myDevice->render_targets[0]) ) {
2829 ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n");
2830 return WINED3DERR_INVALIDCALL;
2833 if(srcSwapchain || SrcSurface == myDevice->render_targets[0]) {
2834 /* Blit from render target to texture */
2836 BOOL upsideDown, stretchx;
2838 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
2839 TRACE("Color keying not supported by frame buffer to texture blit\n");
2840 return WINED3DERR_INVALIDCALL;
2841 /* Destination color key is checked above */
2844 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2845 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2848 if(SrcRect->top < SrcRect->bottom) {
2849 srect.y1 = SrcRect->top;
2850 srect.y2 = SrcRect->bottom;
2853 srect.y1 = SrcRect->bottom;
2854 srect.y2 = SrcRect->top;
2857 srect.x1 = SrcRect->left;
2858 srect.x2 = SrcRect->right;
2862 srect.x2 = Src->currentDesc.Width;
2863 srect.y2 = Src->currentDesc.Height;
2866 if(rect.x1 > rect.x2) {
2870 upsideDown = !upsideDown;
2873 TRACE("Reading from an offscreen target\n");
2874 upsideDown = !upsideDown;
2877 if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
2883 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2884 * flip the image nor scale it.
2886 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2887 * -> If the app wants a image width an unscaled width, copy it line per line
2888 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
2889 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2890 * back buffer. This is slower than reading line per line, thus not used for flipping
2891 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2894 * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
2895 * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
2898 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && GL_SUPPORT(EXT_FRAMEBUFFER_BLIT)) {
2899 stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &srect,
2900 (IWineD3DSurface *)This, &rect, Filter, upsideDown);
2901 } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
2902 rect.y2 - rect.y1 > Src->currentDesc.Height) {
2903 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
2904 fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown, Filter);
2906 TRACE("Using hardware stretching to flip / stretch the texture\n");
2907 fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown, Filter);
2910 if(!(This->Flags & SFLAG_DONOTFREE)) {
2911 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2912 This->resource.allocatedMemory = NULL;
2914 This->Flags &= ~SFLAG_INSYSMEM;
2916 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
2917 * path is never entered
2919 This->Flags |= SFLAG_INTEXTURE;
2923 /* Blit from offscreen surface to render target */
2924 float glTexCoord[4];
2925 DWORD oldCKeyFlags = Src->CKeyFlags;
2926 WINEDDCOLORKEY oldBltCKey = This->SrcBltCKey;
2927 RECT SourceRectangle;
2929 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2932 SourceRectangle.left = SrcRect->left;
2933 SourceRectangle.right = SrcRect->right;
2934 SourceRectangle.top = SrcRect->top;
2935 SourceRectangle.bottom = SrcRect->bottom;
2937 SourceRectangle.left = 0;
2938 SourceRectangle.right = Src->currentDesc.Width;
2939 SourceRectangle.top = 0;
2940 SourceRectangle.bottom = Src->currentDesc.Height;
2943 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2944 /* Fall back to software */
2945 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2946 SourceRectangle.left, SourceRectangle.top,
2947 SourceRectangle.right, SourceRectangle.bottom);
2948 return WINED3DERR_INVALIDCALL;
2951 /* Color keying: Check if we have to do a color keyed blt,
2952 * and if not check if a color key is activated.
2954 * Just modify the color keying parameters in the surface and restore them afterwards
2955 * The surface keeps track of the color key last used to load the opengl surface.
2956 * PreLoad will catch the change to the flags and color key and reload if necessary.
2958 if(Flags & WINEDDBLT_KEYSRC) {
2959 /* Use color key from surface */
2960 } else if(Flags & WINEDDBLT_KEYSRCOVERRIDE) {
2961 /* Use color key from DDBltFx */
2962 Src->CKeyFlags |= WINEDDSD_CKSRCBLT;
2963 This->SrcBltCKey = DDBltFx->ddckSrcColorkey;
2965 /* Do not use color key */
2966 Src->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
2969 /* Now load the surface */
2970 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2974 /* Activate the destination context, set it up for blitting */
2975 ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
2978 TRACE("Drawing to offscreen buffer\n");
2979 glDrawBuffer(myDevice->offscreenBuffer);
2980 checkGLcall("glDrawBuffer");
2982 GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This, (IWineD3DSwapChain *)dstSwapchain);
2983 TRACE("Drawing to %#x buffer\n", buffer);
2984 glDrawBuffer(buffer);
2985 checkGLcall("glDrawBuffer");
2988 /* Bind the texture */
2989 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2990 checkGLcall("glBindTexture");
2992 /* Filtering for StretchRect */
2993 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2994 stateLookup[WINELOOKUP_MAGFILTER][Filter - minLookup[WINELOOKUP_MAGFILTER]]);
2995 checkGLcall("glTexParameteri");
2996 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2997 minMipLookup[Filter][WINED3DTEXF_NONE]);
2998 checkGLcall("glTexParameteri");
2999 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
3000 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
3001 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
3002 checkGLcall("glTexEnvi");
3004 /* This is for color keying */
3005 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3006 glEnable(GL_ALPHA_TEST);
3007 checkGLcall("glEnable GL_ALPHA_TEST");
3008 glAlphaFunc(GL_NOTEQUAL, 0.0);
3009 checkGLcall("glAlphaFunc\n");
3011 glDisable(GL_ALPHA_TEST);
3012 checkGLcall("glDisable GL_ALPHA_TEST");
3015 /* Draw a textured quad
3019 glColor3d(1.0f, 1.0f, 1.0f);
3020 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
3025 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
3026 glVertex3f(rect.x1, rect.y2, 0.0);
3028 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
3033 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
3038 checkGLcall("glEnd");
3040 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3041 glDisable(GL_ALPHA_TEST);
3042 checkGLcall("glDisable(GL_ALPHA_TEST)");
3045 /* Unbind the texture */
3046 glBindTexture(GL_TEXTURE_2D, 0);
3047 checkGLcall("glEnable glBindTexture");
3049 /* The draw buffer should only need to be restored if we were drawing to the front buffer, and there is a back buffer.
3050 * otherwise the context manager should choose between GL_BACK / offscreenDrawBuffer
3052 if(dstSwapchain && This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && dstSwapchain->backBuffer) {
3053 glDrawBuffer(GL_BACK);
3054 checkGLcall("glDrawBuffer");
3056 /* Restore the color key parameters */
3057 Src->CKeyFlags = oldCKeyFlags;
3058 This->SrcBltCKey = oldBltCKey;
3062 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
3063 This->Flags &= ~SFLAG_INSYSMEM;
3064 /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
3067 if(dstSwapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO) {
3068 This->Flags |= SFLAG_INDRAWABLE;
3069 This->Flags &= ~SFLAG_INTEXTURE;
3071 This->Flags |= SFLAG_INTEXTURE;
3076 /* Source-Less Blit to render target */
3077 if (Flags & WINEDDBLT_COLORFILL) {
3078 /* This is easy to handle for the D3D Device... */
3081 TRACE("Colorfill\n");
3083 /* The color as given in the Blt function is in the format of the frame-buffer...
3084 * 'clear' expect it in ARGB format => we need to do some conversion :-)
3086 if (This->resource.format == WINED3DFMT_P8) {
3087 if (This->palette) {
3088 color = ((0xFF000000) |
3089 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
3090 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
3091 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
3096 else if (This->resource.format == WINED3DFMT_R5G6B5) {
3097 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
3100 color = ((0xFF000000) |
3101 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
3102 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
3103 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
3106 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
3107 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
3108 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
3110 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
3111 color = DDBltFx->u5.dwFillColor;
3114 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
3115 return WINED3DERR_INVALIDCALL;
3118 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
3119 if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) {
3120 glDrawBuffer(GL_BACK);
3121 checkGLcall("glDrawBuffer(GL_BACK)");
3122 } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) {
3123 glDrawBuffer(GL_FRONT);
3124 checkGLcall("glDrawBuffer(GL_FRONT)");
3125 } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
3126 glDrawBuffer(myDevice->offscreenBuffer);
3127 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer3)");
3129 TRACE("Surface is higher back buffer, falling back to software\n");
3130 return WINED3DERR_INVALIDCALL;
3133 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
3135 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
3136 1 /* Number of rectangles */,
3138 WINED3DCLEAR_TARGET,
3143 /* Restore the original draw buffer */
3145 glDrawBuffer(myDevice->offscreenBuffer);
3146 } else if(dstSwapchain->backBuffer && dstSwapchain->backBuffer[0]) {
3147 glDrawBuffer(GL_BACK);
3149 vcheckGLcall("glDrawBuffer");
3155 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3156 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3157 return WINED3DERR_INVALIDCALL;
3160 static HRESULT WINAPI IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx)
3162 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3164 if (Flags & WINEDDBLT_DEPTHFILL)
3165 return IWineD3DDevice_Clear((IWineD3DDevice *) myDevice,
3166 DestRect == NULL ? 0 : 1,
3167 (WINED3DRECT *) DestRect,
3168 WINED3DCLEAR_ZBUFFER,
3170 (float) DDBltFx->u5.dwFillDepth / (float) MAXDWORD,
3173 FIXME("(%p): Unsupp depthstencil blit\n", This);
3174 return WINED3DERR_INVALIDCALL;
3177 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
3178 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3179 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3180 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3181 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
3182 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
3184 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair,
3185 * except depth blits, which seem to work
3187 if(iface == myDevice->stencilBufferTarget || (SrcSurface && SrcSurface == myDevice->stencilBufferTarget)) {
3188 if(myDevice->inScene && !(Flags & WINEDDBLT_DEPTHFILL)) {
3189 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3190 return WINED3DERR_INVALIDCALL;
3191 } else if(IWineD3DSurfaceImpl_BltZ(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) {
3192 TRACE("Z Blit override handled the blit\n");
3197 /* Special cases for RenderTargets */
3198 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3199 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
3200 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter) == WINED3D_OK) return WINED3D_OK;
3203 /* For the rest call the X11 surface implementation.
3204 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
3205 * other Blts are rather rare
3207 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter);
3210 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
3211 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3212 TRACE("(%p)->(%x)\n", This, Flags);
3216 case WINEDDGBS_CANBLT:
3217 case WINEDDGBS_ISBLTDONE:
3221 return WINED3DERR_INVALIDCALL;
3225 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
3226 /* XXX: DDERR_INVALIDSURFACETYPE */
3228 TRACE("(%p)->(%08x)\n",iface,Flags);
3230 case WINEDDGFS_CANFLIP:
3231 case WINEDDGFS_ISFLIPDONE:
3235 return WINED3DERR_INVALIDCALL;
3239 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
3240 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3241 TRACE("(%p)\n", This);
3243 /* D3D8 and 9 loose full devices, ddraw only surfaces */
3244 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
3247 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
3248 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3249 TRACE("(%p)\n", This);
3251 /* So far we don't lose anything :) */
3252 This->Flags &= ~SFLAG_LOST;
3256 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
3257 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3258 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
3259 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3260 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
3262 if(myDevice->inScene &&
3263 (iface == myDevice->stencilBufferTarget ||
3264 (Source && Source == myDevice->stencilBufferTarget))) {
3265 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3266 return WINED3DERR_INVALIDCALL;
3269 /* Special cases for RenderTargets */
3270 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3271 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
3273 RECT SrcRect, DstRect;
3277 SrcRect.left = rsrc->left;
3278 SrcRect.top= rsrc->top;
3279 SrcRect.bottom = rsrc->bottom;
3280 SrcRect.right = rsrc->right;
3284 SrcRect.right = srcImpl->currentDesc.Width;
3285 SrcRect.bottom = srcImpl->currentDesc.Height;
3288 DstRect.left = dstx;
3290 DstRect.right = dstx + SrcRect.right - SrcRect.left;
3291 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
3293 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
3294 if(trans & WINEDDBLTFAST_SRCCOLORKEY)
3295 Flags |= WINEDDBLT_KEYSRC;
3296 if(trans & WINEDDBLTFAST_DESTCOLORKEY)
3297 Flags |= WINEDDBLT_KEYDEST;
3298 if(trans & WINEDDBLTFAST_WAIT)
3299 Flags |= WINEDDBLT_WAIT;
3300 if(trans & WINEDDBLTFAST_DONOTWAIT)
3301 Flags |= WINEDDBLT_DONOTWAIT;
3303 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL, WINED3DTEXF_POINT) == WINED3D_OK) return WINED3D_OK;
3307 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
3310 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
3311 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3312 TRACE("(%p)->(%p)\n", This, Pal);
3314 *Pal = (IWineD3DPalette *) This->palette;
3318 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
3319 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3321 IWineD3DPaletteImpl *pal = This->palette;
3323 TRACE("(%p)\n", This);
3325 if(This->resource.format == WINED3DFMT_P8 ||
3326 This->resource.format == WINED3DFMT_A8P8)
3328 if(!This->Flags & SFLAG_INSYSMEM) {
3329 FIXME("Palette changed with surface that does not have an up to date system memory copy\n");
3331 TRACE("Dirtifying surface\n");
3332 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
3335 if(This->Flags & SFLAG_DIBSECTION) {
3336 TRACE("(%p): Updating the hdc's palette\n", This);
3337 for (n=0; n<256; n++) {
3339 col[n].rgbRed = pal->palents[n].peRed;
3340 col[n].rgbGreen = pal->palents[n].peGreen;
3341 col[n].rgbBlue = pal->palents[n].peBlue;
3343 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3344 /* Use the default device palette */
3345 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
3346 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
3347 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
3349 col[n].rgbReserved = 0;
3351 SetDIBColorTable(This->hDC, 0, 256, col);
3357 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
3358 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3359 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
3360 TRACE("(%p)->(%p)\n", This, Pal);
3362 if(This->palette != NULL)
3363 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3364 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
3366 if(PalImpl != NULL) {
3367 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3368 /* Set the device's main palette if the palette
3369 * wasn't a primary palette before
3371 if(!(PalImpl->Flags & WINEDDPCAPS_PRIMARYSURFACE)) {
3372 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3375 for(i=0; i < 256; i++) {
3376 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
3380 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
3383 This->palette = PalImpl;
3385 return IWineD3DSurface_RealizePalette(iface);
3388 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, WINEDDCOLORKEY *CKey) {
3389 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3390 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
3392 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
3393 FIXME(" colorkey value not supported (%08x) !\n", Flags);
3394 return WINED3DERR_INVALIDCALL;
3397 /* Dirtify the surface, but only if a key was changed */
3399 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
3400 case WINEDDCKEY_DESTBLT:
3401 This->DestBltCKey = *CKey;
3402 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
3405 case WINEDDCKEY_DESTOVERLAY:
3406 This->DestOverlayCKey = *CKey;
3407 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
3410 case WINEDDCKEY_SRCOVERLAY:
3411 This->SrcOverlayCKey = *CKey;
3412 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
3415 case WINEDDCKEY_SRCBLT:
3416 This->SrcBltCKey = *CKey;
3417 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
3422 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
3423 case WINEDDCKEY_DESTBLT:
3424 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
3427 case WINEDDCKEY_DESTOVERLAY:
3428 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
3431 case WINEDDCKEY_SRCOVERLAY:
3432 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
3435 case WINEDDCKEY_SRCBLT:
3436 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3444 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3445 /** Check against the maximum texture sizes supported by the video card **/
3446 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3447 unsigned int pow2Width, pow2Height;
3448 const GlPixelFormatDesc *glDesc;
3450 getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc);
3451 /* Setup some glformat defaults */
3452 This->glDescription.glFormat = glDesc->glFormat;
3453 This->glDescription.glFormatInternal = glDesc->glInternal;
3454 This->glDescription.glType = glDesc->glType;
3456 This->glDescription.textureName = 0;
3457 This->glDescription.target = GL_TEXTURE_2D;
3459 /* Non-power2 support */
3460 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
3461 pow2Width = This->currentDesc.Width;
3462 pow2Height = This->currentDesc.Height;
3464 /* Find the nearest pow2 match */
3465 pow2Width = pow2Height = 1;
3466 while (pow2Width < This->currentDesc.Width) pow2Width <<= 1;
3467 while (pow2Height < This->currentDesc.Height) pow2Height <<= 1;
3469 This->pow2Width = pow2Width;
3470 This->pow2Height = pow2Height;
3472 if (pow2Width > This->currentDesc.Width || pow2Height > This->currentDesc.Height) {
3473 WINED3DFORMAT Format = This->resource.format;
3474 /** TODO: add support for non power two compressed textures **/
3475 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
3476 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
3477 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
3478 This, This->currentDesc.Width, This->currentDesc.Height);
3479 return WINED3DERR_NOTAVAILABLE;
3483 if(pow2Width != This->currentDesc.Width ||
3484 pow2Height != This->currentDesc.Height) {
3485 This->Flags |= SFLAG_NONPOW2;
3488 TRACE("%p\n", This);
3489 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3490 /* one of three options
3491 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)
3492 2: Set the texture to the maximum size (bad idea)
3493 3: WARN and return WINED3DERR_NOTAVAILABLE;
3494 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.
3496 WARN("(%p) Creating an oversized surface\n", This);
3497 This->Flags |= SFLAG_OVERSIZE;
3499 /* This will be initialized on the first blt */
3500 This->glRect.left = 0;
3501 This->glRect.top = 0;
3502 This->glRect.right = 0;
3503 This->glRect.bottom = 0;
3505 /* No oversize, gl rect is the full texture size */
3506 This->Flags &= ~SFLAG_OVERSIZE;
3507 This->glRect.left = 0;
3508 This->glRect.top = 0;
3509 This->glRect.right = This->pow2Width;
3510 This->glRect.bottom = This->pow2Height;
3513 if(This->resource.allocatedMemory == NULL) {
3514 /* Make sure memory exists from the start, and it is initialized properly. D3D initializes surfaces,
3515 * gl does not, so we need to upload zeroes to init the gl texture.
3517 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + 4);
3519 This->Flags |= SFLAG_INSYSMEM;
3524 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3525 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3527 TRACE("(%p)\n", This);
3529 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3530 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3531 ie pitch = (width/4) * bytes per block */
3532 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3533 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3534 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3535 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3536 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3538 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
3539 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3540 ret = (ret + alignment - 1) & ~(alignment - 1);
3542 TRACE("(%p) Returning %d\n", This, ret);
3546 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3547 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3549 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3551 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3553 TRACE("(%p): Not an overlay surface\n", This);
3554 return WINEDDERR_NOTAOVERLAYSURFACE;
3560 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3561 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3563 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3565 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3567 TRACE("(%p): Not an overlay surface\n", This);
3568 return WINEDDERR_NOTAOVERLAYSURFACE;
3574 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3575 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3576 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3578 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3580 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3582 TRACE("(%p): Not an overlay surface\n", This);
3583 return WINEDDERR_NOTAOVERLAYSURFACE;
3589 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3590 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3591 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3592 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3594 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3596 TRACE("(%p): Not an overlay surface\n", This);
3597 return WINEDDERR_NOTAOVERLAYSURFACE;
3603 HRESULT WINAPI IWineD3DSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
3605 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3606 TRACE("(%p)->(%p)\n", This, clipper);
3608 This->clipper = clipper;
3612 HRESULT WINAPI IWineD3DSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
3614 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3615 TRACE("(%p)->(%p)\n", This, clipper);
3617 *clipper = This->clipper;
3619 IWineD3DClipper_AddRef(*clipper);
3624 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3627 IWineD3DSurfaceImpl_QueryInterface,
3628 IWineD3DSurfaceImpl_AddRef,
3629 IWineD3DSurfaceImpl_Release,
3630 /* IWineD3DResource */
3631 IWineD3DSurfaceImpl_GetParent,
3632 IWineD3DSurfaceImpl_GetDevice,
3633 IWineD3DSurfaceImpl_SetPrivateData,
3634 IWineD3DSurfaceImpl_GetPrivateData,
3635 IWineD3DSurfaceImpl_FreePrivateData,
3636 IWineD3DSurfaceImpl_SetPriority,
3637 IWineD3DSurfaceImpl_GetPriority,
3638 IWineD3DSurfaceImpl_PreLoad,
3639 IWineD3DSurfaceImpl_GetType,
3640 /* IWineD3DSurface */
3641 IWineD3DSurfaceImpl_GetContainer,
3642 IWineD3DSurfaceImpl_GetDesc,
3643 IWineD3DSurfaceImpl_LockRect,
3644 IWineD3DSurfaceImpl_UnlockRect,
3645 IWineD3DSurfaceImpl_GetDC,
3646 IWineD3DSurfaceImpl_ReleaseDC,
3647 IWineD3DSurfaceImpl_Flip,
3648 IWineD3DSurfaceImpl_Blt,
3649 IWineD3DSurfaceImpl_GetBltStatus,
3650 IWineD3DSurfaceImpl_GetFlipStatus,
3651 IWineD3DSurfaceImpl_IsLost,
3652 IWineD3DSurfaceImpl_Restore,
3653 IWineD3DSurfaceImpl_BltFast,
3654 IWineD3DSurfaceImpl_GetPalette,
3655 IWineD3DSurfaceImpl_SetPalette,
3656 IWineD3DSurfaceImpl_RealizePalette,
3657 IWineD3DSurfaceImpl_SetColorKey,
3658 IWineD3DSurfaceImpl_GetPitch,
3659 IWineD3DSurfaceImpl_SetMem,
3660 IWineD3DSurfaceImpl_SetOverlayPosition,
3661 IWineD3DSurfaceImpl_GetOverlayPosition,
3662 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3663 IWineD3DSurfaceImpl_UpdateOverlay,
3664 IWineD3DSurfaceImpl_SetClipper,
3665 IWineD3DSurfaceImpl_GetClipper,
3667 IWineD3DSurfaceImpl_AddDirtyRect,
3668 IWineD3DSurfaceImpl_LoadTexture,
3669 IWineD3DSurfaceImpl_SaveSnapshot,
3670 IWineD3DSurfaceImpl_SetContainer,
3671 IWineD3DSurfaceImpl_SetGlTextureDesc,
3672 IWineD3DSurfaceImpl_GetGlDesc,
3673 IWineD3DSurfaceImpl_GetData,
3674 IWineD3DSurfaceImpl_SetFormat,
3675 IWineD3DSurfaceImpl_PrivateSetup