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) || (This->Flags & SFLAG_INSYSMEM)) {
767 TRACE("WINED3DLOCK_DISCARD flag passed, or local copy is up to date, not downloading data\n");
771 /* Now download the surface content from opengl
772 * Use the render target readback if the surface is on a swapchain(=onscreen render target) or the current primary target
773 * Offscreen targets which are not active at the moment or are higher targets(fbos) can be locked with the texture path
775 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
776 if(swapchain || iface == myDevice->render_targets[0]) {
777 BOOL srcIsUpsideDown;
779 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
780 static BOOL warned = FALSE;
782 ERR("The application tries to lock the render target, but render target locking is disabled\n");
785 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
789 /* Activate the surface. Set it up for blitting now, although not necessarily needed for LockRect.
790 * Certain graphics drivers seem to dislike some enabled states when reading from opengl, the blitting usage
791 * should help here. Furthermore unlockrect will need the context set up for blitting. The context manager will find
792 * context->last_was_blit set on the unlock.
795 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
797 /* Select the correct read buffer, and give some debug output.
798 * There is no need to keep track of the current read buffer or reset it, every part of the code
799 * that reads sets the read buffer as desired.
802 /* Locking the primary render target which is not on a swapchain(=offscreen render target).
803 * Read from the back buffer
805 TRACE("Locking offscreen render target\n");
806 glReadBuffer(myDevice->offscreenBuffer);
807 srcIsUpsideDown = TRUE;
809 GLenum buffer = surface_get_gl_buffer(iface, (IWineD3DSwapChain *)swapchain);
810 TRACE("Locking %#x buffer\n", buffer);
811 glReadBuffer(buffer);
812 checkGLcall("glReadBuffer");
814 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
815 srcIsUpsideDown = FALSE;
818 switch(wined3d_settings.rendertargetlock_mode) {
822 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
827 read_from_framebuffer(This, &This->lockedRect, This->resource.allocatedMemory, pLockedRect->Pitch, srcIsUpsideDown);
828 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
833 /* Mark the local copy up to date if a full download was done */
834 if(This->lockedRect.left == 0 &&
835 This->lockedRect.top == 0 &&
836 This->lockedRect.right == This->currentDesc.Width &&
837 This->lockedRect.bottom == This->currentDesc.Height) {
838 This->Flags |= SFLAG_INSYSMEM;
840 } else if(iface == myDevice->stencilBufferTarget) {
841 /** the depth stencil in openGL has a format of GL_FLOAT
842 * which should be good for WINED3DFMT_D16_LOCKABLE
844 * it is unclear what format the stencil buffer is in except.
845 * 'Each index is converted to fixed point...
846 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
847 * mappings in the table GL_PIXEL_MAP_S_TO_S.
848 * glReadPixels(This->lockedRect.left,
849 * This->lockedRect.bottom - j - 1,
850 * This->lockedRect.right - This->lockedRect.left,
852 * GL_DEPTH_COMPONENT,
854 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
856 * Depth Stencil surfaces which are not the current depth stencil target should have their data in a
857 * gl texture(next path), or in local memory(early return because of set SFLAG_INSYSMEM above). If
858 * none of that is the case the problem is not in this function :-)
859 ********************************************/
860 FIXME("Depth stencil locking not supported yet\n");
862 /* This path is for normal surfaces, offscreen render targets and everything else that is in a gl texture */
863 TRACE("locking an ordinary surface\n");
865 if (0 != This->glDescription.textureName) {
866 /* Now I have to copy thing bits back */
870 if(myDevice->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
871 ActivateContext(myDevice, myDevice->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
874 /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
875 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
876 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
877 checkGLcall("glActiveTextureARB");
879 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
880 IWineD3DSurface_PreLoad(iface);
882 surface_download_data(This);
888 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
891 IWineD3DBaseTexture *pBaseTexture;
894 * as seen in msdn docs
896 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
898 /** Dirtify Container if needed */
899 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
900 TRACE("Making container dirty\n");
901 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
902 IWineD3DBaseTexture_Release(pBaseTexture);
904 TRACE("Surface is standalone, no need to dirty the container\n");
908 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch,
909 This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
913 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
915 GLint prev_rasterpos[4];
917 BOOL storechanged = FALSE, memory_allocated = FALSE;
921 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
923 glDisable(GL_TEXTURE_2D);
924 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
927 vcheckGLcall("glFlush");
928 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
929 vcheckGLcall("glIntegerv");
930 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
931 vcheckGLcall("glIntegerv");
932 glPixelZoom(1.0, -1.0);
933 vcheckGLcall("glPixelZoom");
935 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
936 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
937 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
939 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
940 vcheckGLcall("glRasterPos2f");
942 /* Some drivers(radeon dri, others?) don't like exceptions during
943 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
944 * after ReleaseDC. Reading it will cause an exception, which x11drv will
945 * catch to put the dib section in InSync mode, which leads to a crash
946 * and a blocked x server on my radeon card.
948 * The following lines read the dib section so it is put in inSync mode
949 * before glDrawPixels is called and the crash is prevented. There won't
950 * be any interfering gdi accesses, because UnlockRect is called from
951 * ReleaseDC, and the app won't use the dc any more afterwards.
953 if(This->Flags & SFLAG_DIBSECTION) {
955 read = This->resource.allocatedMemory[0];
958 switch (This->resource.format) {
959 /* No special care needed */
960 case WINED3DFMT_A4R4G4B4:
961 case WINED3DFMT_R5G6B5:
962 case WINED3DFMT_A1R5G5B5:
963 case WINED3DFMT_R8G8B8:
964 type = This->glDescription.glType;
965 fmt = This->glDescription.glFormat;
966 mem = This->resource.allocatedMemory;
967 bpp = This->bytesPerPixel;
970 case WINED3DFMT_X4R4G4B4:
973 unsigned short *data;
974 data = (unsigned short *)This->resource.allocatedMemory;
975 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
981 type = This->glDescription.glType;
982 fmt = This->glDescription.glFormat;
983 mem = This->resource.allocatedMemory;
984 bpp = This->bytesPerPixel;
988 case WINED3DFMT_X1R5G5B5:
991 unsigned short *data;
992 data = (unsigned short *)This->resource.allocatedMemory;
993 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
999 type = This->glDescription.glType;
1000 fmt = This->glDescription.glFormat;
1001 mem = This->resource.allocatedMemory;
1002 bpp = This->bytesPerPixel;
1006 case WINED3DFMT_X8R8G8B8:
1008 /* make sure the X byte is set to alpha on, since it
1009 could be any random value. This fixes the intro movie in Pirates! */
1012 data = (unsigned int *)This->resource.allocatedMemory;
1013 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
1015 *data |= 0xFF000000;
1022 case WINED3DFMT_A8R8G8B8:
1024 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
1025 vcheckGLcall("glPixelStorei");
1026 storechanged = TRUE;
1027 type = This->glDescription.glType;
1028 fmt = This->glDescription.glFormat;
1029 mem = This->resource.allocatedMemory;
1030 bpp = This->bytesPerPixel;
1034 case WINED3DFMT_A2R10G10B10:
1036 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
1037 vcheckGLcall("glPixelStorei");
1038 storechanged = TRUE;
1039 type = This->glDescription.glType;
1040 fmt = This->glDescription.glFormat;
1041 mem = This->resource.allocatedMemory;
1042 bpp = This->bytesPerPixel;
1048 int height = This->glRect.bottom - This->glRect.top;
1049 type = GL_UNSIGNED_BYTE;
1052 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
1054 ERR("Out of memory\n");
1057 memory_allocated = TRUE;
1058 d3dfmt_convert_surface(This->resource.allocatedMemory,
1066 bpp = This->bytesPerPixel * 4;
1072 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
1075 type = This->glDescription.glType;
1076 fmt = This->glDescription.glFormat;
1077 mem = This->resource.allocatedMemory;
1078 bpp = This->bytesPerPixel;
1081 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1082 (This->lockedRect.bottom - This->lockedRect.top)-1,
1084 mem + bpp * This->lockedRect.left + pitch * This->lockedRect.top);
1085 checkGLcall("glDrawPixels");
1086 glPixelZoom(1.0,1.0);
1087 vcheckGLcall("glPixelZoom");
1089 glRasterPos3iv(&prev_rasterpos[0]);
1090 vcheckGLcall("glRasterPos3iv");
1092 /* Reset to previous pack row length */
1093 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1094 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1096 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
1097 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1100 /* Blitting environment requires that 2D texturing is enabled. It was turned off before,
1103 glEnable(GL_TEXTURE_2D);
1104 checkGLcall("glEnable(GL_TEXTURE_2D)");
1106 if(memory_allocated) HeapFree(GetProcessHeap(), 0, mem);
1110 static void flush_to_framebuffer_texture(IWineD3DSurfaceImpl *This) {
1111 float glTexCoord[4];
1113 glTexCoord[0] = (float) This->lockedRect.left / (float) This->pow2Width; /* left */
1114 glTexCoord[1] = (float) This->lockedRect.right / (float) This->pow2Width; /* right */
1115 glTexCoord[2] = (float) This->lockedRect.top / (float) This->pow2Height; /* top */
1116 glTexCoord[3] = (float) This->lockedRect.bottom / (float) This->pow2Height; /* bottom */
1118 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
1122 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1123 checkGLcall("glEnable glBindTexture");
1125 /* No filtering for blts */
1126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1127 checkGLcall("glTexParameteri");
1128 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1129 checkGLcall("glTexParameteri");
1131 /* Start drawing a quad */
1134 glColor3d(1.0f, 1.0f, 1.0f);
1135 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1136 glVertex3f(This->lockedRect.left, This->lockedRect.top, 0.0);
1138 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1139 glVertex3f(This->lockedRect.left, This->lockedRect.bottom, 0.0);
1141 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1142 glVertex3d(This->lockedRect.right, This->lockedRect.bottom, 0.0);
1144 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1145 glVertex3f(This->lockedRect.right, This->lockedRect.top, 0.0);
1148 checkGLcall("glEnd");
1150 /* Unbind the texture */
1151 glBindTexture(GL_TEXTURE_2D, 0);
1152 checkGLcall("glEnable glBindTexture");
1157 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1158 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1159 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1160 IWineD3DSwapChainImpl *swapchain = NULL;
1162 if (!(This->Flags & SFLAG_LOCKED)) {
1163 WARN("trying to Unlock an unlocked surf@%p\n", This);
1164 return WINED3DERR_INVALIDCALL;
1167 TRACE("(%p) : dirtyfied(%d)\n", This, This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE) ? 0 : 1);
1169 if (This->Flags & (SFLAG_INDRAWABLE | SFLAG_INTEXTURE)) {
1170 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1174 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1175 if(swapchain || iface == myDevice->render_targets[0]) {
1176 if(wined3d_settings.rendertargetlock_mode == RTL_DISABLE) {
1177 static BOOL warned = FALSE;
1179 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1182 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
1186 /* Activate the correct context for the render target */
1188 ActivateContext(myDevice, iface, CTXUSAGE_BLIT);
1191 /* Primary offscreen render target */
1192 TRACE("Offscreen render target\n");
1193 glDrawBuffer(myDevice->offscreenBuffer);
1194 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1196 GLenum buffer = surface_get_gl_buffer(iface, (IWineD3DSwapChain *)swapchain);
1197 TRACE("Unlocking %#x buffer\n", buffer);
1198 glDrawBuffer(buffer);
1199 checkGLcall("glDrawBuffer");
1201 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1204 switch(wined3d_settings.rendertargetlock_mode) {
1208 flush_to_framebuffer_drawpixels(This);
1213 flush_to_framebuffer_texture(This);
1217 glDrawBuffer(myDevice->offscreenBuffer);
1218 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer)");
1219 } else if(swapchain->backBuffer) {
1220 glDrawBuffer(GL_BACK);
1221 checkGLcall("glDrawBuffer(GL_BACK)");
1223 glDrawBuffer(GL_FRONT);
1224 checkGLcall("glDrawBuffer(GL_FRONT)");
1228 This->dirtyRect.left = This->currentDesc.Width;
1229 This->dirtyRect.top = This->currentDesc.Height;
1230 This->dirtyRect.right = 0;
1231 This->dirtyRect.bottom = 0;
1232 This->Flags |= SFLAG_INDRAWABLE;
1233 } else if(iface == myDevice->stencilBufferTarget) {
1234 FIXME("Depth Stencil buffer locking is not implemented\n");
1236 /* The rest should be a normal texture */
1237 IWineD3DBaseTextureImpl *impl;
1238 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1239 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1240 * states need resetting
1242 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1243 if(impl->baseTexture.bindCount) {
1244 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1246 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1251 This->Flags &= ~SFLAG_LOCKED;
1252 memset(&This->lockedRect, 0, sizeof(RECT));
1256 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1257 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1258 WINED3DLOCKED_RECT lock;
1265 const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format, NULL, NULL);
1267 TRACE("(%p)->(%p)\n",This,pHDC);
1269 if(This->Flags & SFLAG_USERPTR) {
1270 ERR("Not supported on surfaces with an application-provided surfaces\n");
1271 return WINEDDERR_NODC;
1274 /* Give more detailed info for ddraw */
1275 if (This->Flags & SFLAG_DCINUSE)
1276 return WINEDDERR_DCALREADYCREATED;
1278 /* Can't GetDC if the surface is locked */
1279 if (This->Flags & SFLAG_LOCKED)
1280 return WINED3DERR_INVALIDCALL;
1282 memset(&lock, 0, sizeof(lock)); /* To be sure */
1284 /* Create a DIB section if there isn't a hdc yet */
1287 SYSTEM_INFO sysInfo;
1288 void *oldmem = This->resource.allocatedMemory;
1290 switch (This->bytesPerPixel) {
1293 /* Allocate extra space to store the RGB bit masks. */
1294 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1298 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1302 /* Allocate extra space for a palette. */
1303 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1304 sizeof(BITMAPINFOHEADER)
1306 * (1 << (This->bytesPerPixel * 8)));
1311 return E_OUTOFMEMORY;
1313 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1314 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1315 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1316 * add an extra line to the dib section
1318 GetSystemInfo(&sysInfo);
1319 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1321 TRACE("Adding an extra line to the dib section\n");
1324 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1325 /* TODO: Is there a nicer way to force a specific alignment? (8 byte for ddraw) */
1326 b_info->bmiHeader.biWidth = IWineD3DSurface_GetPitch(iface) / This->bytesPerPixel;
1327 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1328 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1329 b_info->bmiHeader.biPlanes = 1;
1330 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1332 b_info->bmiHeader.biXPelsPerMeter = 0;
1333 b_info->bmiHeader.biYPelsPerMeter = 0;
1334 b_info->bmiHeader.biClrUsed = 0;
1335 b_info->bmiHeader.biClrImportant = 0;
1337 /* Get the bit masks */
1338 masks = (DWORD *) &(b_info->bmiColors);
1339 switch (This->resource.format) {
1340 case WINED3DFMT_R8G8B8:
1341 usage = DIB_RGB_COLORS;
1342 b_info->bmiHeader.biCompression = BI_RGB;
1345 case WINED3DFMT_X1R5G5B5:
1346 case WINED3DFMT_A1R5G5B5:
1347 case WINED3DFMT_A4R4G4B4:
1348 case WINED3DFMT_X4R4G4B4:
1349 case WINED3DFMT_R3G3B2:
1350 case WINED3DFMT_A8R3G3B2:
1351 case WINED3DFMT_A2B10G10R10:
1352 case WINED3DFMT_A8B8G8R8:
1353 case WINED3DFMT_X8B8G8R8:
1354 case WINED3DFMT_A2R10G10B10:
1355 case WINED3DFMT_R5G6B5:
1356 case WINED3DFMT_A16B16G16R16:
1358 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1359 masks[0] = formatEntry->redMask;
1360 masks[1] = formatEntry->greenMask;
1361 masks[2] = formatEntry->blueMask;
1365 /* Don't know palette */
1366 b_info->bmiHeader.biCompression = BI_RGB;
1373 HeapFree(GetProcessHeap(), 0, b_info);
1374 return HRESULT_FROM_WIN32(GetLastError());
1377 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);
1378 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1381 if (!This->dib.DIBsection) {
1382 ERR("CreateDIBSection failed!\n");
1383 HeapFree(GetProcessHeap(), 0, b_info);
1384 return HRESULT_FROM_WIN32(GetLastError());
1387 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1389 /* copy the existing surface to the dib section */
1390 if(This->resource.allocatedMemory) {
1391 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1392 /* We won't need that any more */
1394 /* This is to make LockRect read the gl Texture although memory is allocated */
1395 This->Flags &= ~SFLAG_INSYSMEM;
1398 HeapFree(GetProcessHeap(), 0, b_info);
1400 /* Use the dib section from now on */
1401 This->resource.allocatedMemory = This->dib.bitmap_data;
1403 /* Now allocate a HDC */
1404 This->hDC = CreateCompatibleDC(0);
1405 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1406 TRACE("using wined3d palette %p\n", This->palette);
1407 SelectPalette(This->hDC,
1408 This->palette ? This->palette->hpal : 0,
1411 This->Flags |= SFLAG_DIBSECTION;
1413 if(This->Flags & SFLAG_CLIENT) {
1414 IWineD3DSurface_PreLoad(iface);
1416 HeapFree(GetProcessHeap(), 0, oldmem);
1419 /* Lock the surface */
1420 hr = IWineD3DSurface_LockRect(iface,
1425 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1426 /* keep the dib section */
1430 if(This->resource.format == WINED3DFMT_P8 ||
1431 This->resource.format == WINED3DFMT_A8P8) {
1434 PALETTEENTRY ent[256];
1436 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1437 for (n=0; n<256; n++) {
1438 col[n].rgbRed = ent[n].peRed;
1439 col[n].rgbGreen = ent[n].peGreen;
1440 col[n].rgbBlue = ent[n].peBlue;
1441 col[n].rgbReserved = 0;
1444 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1446 for (n=0; n<256; n++) {
1447 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1448 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1449 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1450 col[n].rgbReserved = 0;
1454 SetDIBColorTable(This->hDC, 0, 256, col);
1458 TRACE("returning %p\n",*pHDC);
1459 This->Flags |= SFLAG_DCINUSE;
1464 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1465 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1467 TRACE("(%p)->(%p)\n",This,hDC);
1469 if (!(This->Flags & SFLAG_DCINUSE))
1470 return WINED3DERR_INVALIDCALL;
1472 /* we locked first, so unlock now */
1473 IWineD3DSurface_UnlockRect(iface);
1475 This->Flags &= ~SFLAG_DCINUSE;
1480 /* ******************************************************
1481 IWineD3DSurface Internal (No mapping to directx api) parts follow
1482 ****************************************************** */
1484 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) {
1485 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & WINEDDSD_CKSRCBLT);
1486 const GlPixelFormatDesc *glDesc;
1487 getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc);
1489 /* Default values: From the surface */
1490 *format = glDesc->glFormat;
1491 *internal = srgb_mode?glDesc->glGammaInternal:glDesc->glInternal;
1492 *type = glDesc->glType;
1493 *convert = NO_CONVERSION;
1494 *target_bpp = This->bytesPerPixel;
1496 /* Ok, now look if we have to do any conversion */
1497 switch(This->resource.format) {
1502 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1503 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1505 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1507 *internal = GL_RGBA;
1508 *type = GL_UNSIGNED_BYTE;
1510 if(colorkey_active) {
1511 *convert = CONVERT_PALETTED_CK;
1513 *convert = CONVERT_PALETTED;
1519 case WINED3DFMT_R3G3B2:
1520 /* **********************
1521 GL_UNSIGNED_BYTE_3_3_2
1522 ********************** */
1523 if (colorkey_active) {
1524 /* This texture format will never be used.. So do not care about color keying
1525 up until the point in time it will be needed :-) */
1526 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1530 case WINED3DFMT_R5G6B5:
1531 if (colorkey_active) {
1532 *convert = CONVERT_CK_565;
1534 *internal = GL_RGBA;
1535 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1539 case WINED3DFMT_X1R5G5B5:
1540 if (colorkey_active) {
1541 *convert = CONVERT_CK_5551;
1543 *internal = GL_RGBA;
1544 *type = GL_UNSIGNED_SHORT_1_5_5_5_REV;
1548 case WINED3DFMT_R8G8B8:
1549 if (colorkey_active) {
1550 *convert = CONVERT_CK_RGB24;
1552 *internal = GL_RGBA;
1553 *type = GL_UNSIGNED_INT_8_8_8_8;
1558 case WINED3DFMT_X8R8G8B8:
1559 if (colorkey_active) {
1560 *convert = CONVERT_RGB32_888;
1562 *internal = GL_RGBA;
1563 *type = GL_UNSIGNED_INT_8_8_8_8;
1567 case WINED3DFMT_V8U8:
1568 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1569 else if(GL_SUPPORT(ATI_ENVMAP_BUMPMAP)) {
1570 *format = GL_DUDV_ATI;
1571 *internal = GL_DU8DV8_ATI;
1573 /* No conversion - Just change the gl type */
1576 *convert = CONVERT_V8U8;
1578 *internal = GL_RGB8;
1579 *type = GL_UNSIGNED_BYTE;
1583 case WINED3DFMT_X8L8V8U8:
1584 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1585 *convert = CONVERT_X8L8V8U8;
1587 *internal = GL_RGBA8;
1588 *type = GL_UNSIGNED_BYTE;
1590 /* Not supported by GL_ATI_envmap_bumpmap */
1593 case WINED3DFMT_Q8W8V8U8:
1594 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1595 *convert = CONVERT_Q8W8V8U8;
1597 *internal = GL_RGBA8;
1598 *type = GL_UNSIGNED_BYTE;
1600 /* Not supported by GL_ATI_envmap_bumpmap */
1603 case WINED3DFMT_V16U16:
1604 if(GL_SUPPORT(NV_TEXTURE_SHADER3)) break;
1605 *convert = CONVERT_V16U16;
1607 *internal = GL_RGB16;
1610 /* What should I do here about GL_ATI_envmap_bumpmap?
1611 * Convert it or allow data loss by loading it into a 8 bit / channel texture?
1622 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1623 BYTE *source, *dest;
1624 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1629 memcpy(dst, src, pitch * height);
1632 case CONVERT_PALETTED:
1633 case CONVERT_PALETTED_CK:
1635 IWineD3DPaletteImpl* pal = surf->palette;
1641 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1645 /* Still no palette? Use the device's palette */
1646 /* Get the surface's palette */
1647 for (i = 0; i < 256; i++) {
1648 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1650 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1651 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1652 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1653 if ((convert == CONVERT_PALETTED_CK) &&
1654 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1655 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1656 /* We should maybe here put a more 'neutral' color than the standard bright purple
1657 one often used by application to prevent the nice purple borders when bi-linear
1665 TRACE("Using surface palette %p\n", pal);
1666 /* Get the surface's palette */
1667 for (i = 0; i < 256; i++) {
1668 table[i][0] = pal->palents[i].peRed;
1669 table[i][1] = pal->palents[i].peGreen;
1670 table[i][2] = pal->palents[i].peBlue;
1671 if ((convert == CONVERT_PALETTED_CK) &&
1672 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1673 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1674 /* We should maybe here put a more 'neutral' color than the standard bright purple
1675 one often used by application to prevent the nice purple borders when bi-linear
1678 } else if(pal->Flags & WINEDDPCAPS_ALPHA) {
1679 table[i][3] = pal->palents[i].peFlags;
1686 for (y = 0; y < height; y++)
1688 source = src + pitch * y;
1689 dest = dst + outpitch * y;
1690 /* This is an 1 bpp format, using the width here is fine */
1691 for (x = 0; x < width; x++) {
1692 BYTE color = *source++;
1693 *dest++ = table[color][0];
1694 *dest++ = table[color][1];
1695 *dest++ = table[color][2];
1696 *dest++ = table[color][3];
1702 case CONVERT_CK_565:
1704 /* Converting the 565 format in 5551 packed to emulate color-keying.
1706 Note : in all these conversion, it would be best to average the averaging
1707 pixels to get the color of the pixel that will be color-keyed to
1708 prevent 'color bleeding'. This will be done later on if ever it is
1711 Note2: Nvidia documents say that their driver does not support alpha + color keying
1712 on the same surface and disables color keying in such a case
1718 TRACE("Color keyed 565\n");
1720 for (y = 0; y < height; y++) {
1721 Source = (WORD *) (src + y * pitch);
1722 Dest = (WORD *) (dst + y * outpitch);
1723 for (x = 0; x < width; x++ ) {
1724 WORD color = *Source++;
1725 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1726 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1727 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1736 case CONVERT_CK_5551:
1738 /* Converting X1R5G5B5 format to R5G5B5A1 to emulate color-keying. */
1742 TRACE("Color keyed 5551\n");
1743 for (y = 0; y < height; y++) {
1744 Source = (WORD *) (src + y * pitch);
1745 Dest = (WORD *) (dst + y * outpitch);
1746 for (x = 0; x < width; x++ ) {
1747 WORD color = *Source++;
1749 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1750 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1754 *Dest &= ~(1 << 15);
1766 unsigned char *Dest;
1767 for(y = 0; y < height; y++) {
1768 Source = (short *) (src + y * pitch);
1769 Dest = (unsigned char *) (dst + y * outpitch);
1770 for (x = 0; x < width; x++ ) {
1771 long color = (*Source++);
1772 /* B */ Dest[0] = 0xff;
1773 /* G */ Dest[1] = (color >> 8) + 128; /* V */
1774 /* R */ Dest[2] = (color) + 128; /* U */
1781 case CONVERT_Q8W8V8U8:
1785 unsigned char *Dest;
1786 for(y = 0; y < height; y++) {
1787 Source = (DWORD *) (src + y * pitch);
1788 Dest = (unsigned char *) (dst + y * outpitch);
1789 for (x = 0; x < width; x++ ) {
1790 long color = (*Source++);
1791 /* B */ Dest[0] = ((color >> 16) & 0xff) + 128; /* W */
1792 /* G */ Dest[1] = ((color >> 8 ) & 0xff) + 128; /* V */
1793 /* R */ Dest[2] = (color & 0xff) + 128; /* U */
1794 /* A */ Dest[3] = ((color >> 24) & 0xff) + 128; /* Q */
1802 ERR("Unsupported conversation type %d\n", convert);
1807 /* This function is used in case of 8bit paletted textures to upload the palette.
1808 For now it only supports GL_EXT_paletted_texture extension but support for other
1809 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1811 static void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1812 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1813 IWineD3DPaletteImpl* pal = This->palette;
1818 /* Still no palette? Use the device's palette */
1819 /* Get the surface's palette */
1820 for (i = 0; i < 256; i++) {
1821 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1823 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1824 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1825 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1826 if ((convert == CONVERT_PALETTED_CK) &&
1827 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1828 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1829 /* We should maybe here put a more 'neutral' color than the standard bright purple
1830 one often used by application to prevent the nice purple borders when bi-linear
1838 TRACE("Using surface palette %p\n", pal);
1839 /* Get the surface's palette */
1840 for (i = 0; i < 256; i++) {
1841 table[i][0] = pal->palents[i].peRed;
1842 table[i][1] = pal->palents[i].peGreen;
1843 table[i][2] = pal->palents[i].peBlue;
1844 if ((convert == CONVERT_PALETTED_CK) &&
1845 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1846 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1847 /* We should maybe here put a more 'neutral' color than the standard bright purple
1848 one often used by application to prevent the nice purple borders when bi-linear
1851 } else if(pal->Flags & WINEDDPCAPS_ALPHA) {
1852 table[i][3] = pal->palents[i].peFlags;
1858 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1861 static BOOL palette9_changed(IWineD3DSurfaceImpl *This) {
1862 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1864 if(This->palette || (This->resource.format != WINED3DFMT_P8 && This->resource.format != WINED3DFMT_A8P8)) {
1865 /* If a ddraw-style palette is attached assume no d3d9 palette change.
1866 * Also the palette isn't interesting if the surface format isn't P8 or A8P8
1871 if(This->palette9) {
1872 if(memcmp(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256) == 0) {
1876 This->palette9 = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
1878 memcpy(This->palette9, &device->palettes[device->currentPalette], sizeof(PALETTEENTRY) * 256);
1882 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface, BOOL srgb_mode) {
1883 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1884 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1885 GLenum format, internal, type;
1886 CONVERT_TYPES convert;
1888 int width, pitch, outpitch;
1891 if (!(This->Flags & SFLAG_INTEXTURE)) {
1892 TRACE("Reloading because surface is dirty\n");
1893 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1894 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & WINEDDSD_CKSRCBLT))) ||
1895 /* Reload: vice versa OR */
1896 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & WINEDDSD_CKSRCBLT)) ||
1897 /* Also reload: Color key is active AND the color key has changed */
1898 ((This->CKeyFlags & WINEDDSD_CKSRCBLT) && (
1899 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1900 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1901 TRACE("Reloading because of color keying\n");
1902 } else if(palette9_changed(This)) {
1903 TRACE("Reloading surface because the d3d8/9 palette was changed\n");
1905 TRACE("surface is already in texture\n");
1909 This->Flags |= SFLAG_INTEXTURE;
1911 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1912 * These resources are not bound by device size or format restrictions. Because of this,
1913 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1914 * However, these resources can always be created, locked, and copied.
1916 if (This->resource.pool == WINED3DPOOL_SCRATCH )
1918 FIXME("(%p) Operation not supported for scratch textures\n",This);
1919 return WINED3DERR_INVALIDCALL;
1922 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp, srgb_mode);
1924 if (This->Flags & SFLAG_INDRAWABLE) {
1925 if (This->glDescription.level != 0)
1926 FIXME("Surface in texture is only supported for level 0\n");
1927 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1928 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1929 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1930 This->resource.format == WINED3DFMT_DXT5)
1931 FIXME("Format %d not supported\n", This->resource.format);
1936 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1937 vcheckGLcall("glGetIntegerv");
1938 glReadBuffer(This->resource.wineD3DDevice->offscreenBuffer);
1939 vcheckGLcall("glReadBuffer");
1941 if(!(This->Flags & SFLAG_ALLOCATED)) {
1942 surface_allocate_surface(This, internal, This->pow2Width,
1943 This->pow2Height, format, type);
1946 glCopyTexSubImage2D(This->glDescription.target,
1947 This->glDescription.level,
1949 This->currentDesc.Width,
1950 This->currentDesc.Height);
1951 checkGLcall("glCopyTexSubImage2D");
1953 glReadBuffer(prevRead);
1954 vcheckGLcall("glReadBuffer");
1958 TRACE("Updated target %d\n", This->glDescription.target);
1962 /* The only place where LoadTexture() might get called when isInDraw=1
1963 * is ActivateContext where lastActiveRenderTarget is preloaded.
1965 if(iface == device->lastActiveRenderTarget && device->isInDraw)
1966 ERR("Reading back render target but SFLAG_INDRAWABLE not set\n");
1968 /* Otherwise: System memory copy must be most up to date */
1970 if(This->CKeyFlags & WINEDDSD_CKSRCBLT) {
1971 This->Flags |= SFLAG_GLCKEY;
1972 This->glCKey = This->SrcBltCKey;
1974 else This->Flags &= ~SFLAG_GLCKEY;
1976 /* The width is in 'length' not in bytes */
1977 width = This->currentDesc.Width;
1978 pitch = IWineD3DSurface_GetPitch(iface);
1980 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1981 int height = This->currentDesc.Height;
1983 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1984 outpitch = width * bpp;
1985 outpitch = (outpitch + device->surface_alignment - 1) & ~(device->surface_alignment - 1);
1987 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1989 ERR("Out of memory %d, %d!\n", outpitch, height);
1990 return WINED3DERR_OUTOFVIDEOMEMORY;
1992 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1994 This->Flags |= SFLAG_CONVERTED;
1995 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1996 d3dfmt_p8_upload_palette(iface, convert);
1997 This->Flags &= ~SFLAG_CONVERTED;
1998 mem = This->resource.allocatedMemory;
2000 This->Flags &= ~SFLAG_CONVERTED;
2001 mem = This->resource.allocatedMemory;
2004 /* Make sure the correct pitch is used */
2005 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
2007 if ((This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
2008 TRACE("non power of two support\n");
2009 if(!(This->Flags & SFLAG_ALLOCATED)) {
2010 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
2013 surface_upload_data(This, internal, This->currentDesc.Width, This->currentDesc.Height, format, type, mem);
2016 /* When making the realloc conditional, keep in mind that GL_APPLE_client_storage may be in use, and This->resource.allocatedMemory
2017 * changed. So also keep track of memory changes. In this case the texture has to be reallocated
2019 if(!(This->Flags & SFLAG_ALLOCATED)) {
2020 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
2023 surface_upload_data(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
2027 /* Restore the default pitch */
2028 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
2030 if (mem != This->resource.allocatedMemory)
2031 HeapFree(GetProcessHeap(), 0, mem);
2035 static unsigned int gen = 0;
2038 if ((gen % 10) == 0) {
2039 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
2040 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
2043 * debugging crash code
2052 if (!(This->Flags & SFLAG_DONOTFREE)) {
2053 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2054 This->resource.allocatedMemory = NULL;
2055 This->Flags &= ~SFLAG_INSYSMEM;
2063 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
2066 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2067 char *allocatedMemory;
2069 IWineD3DSwapChain *swapChain = NULL;
2071 GLuint tmpTexture = 0;
2074 Textures may not be stored in ->allocatedgMemory and a GlTexture
2075 so we should lock the surface before saving a snapshot, or at least check that
2077 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
2078 by calling GetTexImage and in compressed form by calling
2079 GetCompressedTexImageARB. Queried compressed images can be saved and
2080 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
2081 texture images do not need to be processed by the GL and should
2082 significantly improve texture loading performance relative to uncompressed
2085 /* Setup the width and height to be the internal texture width and height. */
2086 width = This->pow2Width;
2087 height = This->pow2Height;
2088 /* check to see if we're a 'virtual' texture, e.g. we're not a pbuffer of texture, we're a back buffer*/
2089 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
2091 if (This->Flags & SFLAG_INDRAWABLE && !(This->Flags & SFLAG_INTEXTURE)) {
2092 /* if were not a real texture then read the back buffer into a real texture */
2093 /* we don't want to interfere with the back buffer so read the data into a temporary
2094 * texture and then save the data out of the temporary texture
2098 TRACE("(%p) Reading render target into texture\n", This);
2099 glEnable(GL_TEXTURE_2D);
2101 glGenTextures(1, &tmpTexture);
2102 glBindTexture(GL_TEXTURE_2D, tmpTexture);
2104 glTexImage2D(GL_TEXTURE_2D,
2111 GL_UNSIGNED_INT_8_8_8_8_REV,
2114 glGetIntegerv(GL_READ_BUFFER, &prevRead);
2115 vcheckGLcall("glGetIntegerv");
2116 glReadBuffer(swapChain ? GL_BACK : This->resource.wineD3DDevice->offscreenBuffer);
2117 vcheckGLcall("glReadBuffer");
2118 glCopyTexImage2D(GL_TEXTURE_2D,
2127 checkGLcall("glCopyTexImage2D");
2128 glReadBuffer(prevRead);
2131 } else { /* bind the real texture, and make sure it up to date */
2132 IWineD3DSurface_PreLoad(iface);
2134 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
2136 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
2137 glGetTexImage(GL_TEXTURE_2D,
2138 This->glDescription.level,
2140 GL_UNSIGNED_INT_8_8_8_8_REV,
2142 checkGLcall("glTexImage2D");
2144 glBindTexture(GL_TEXTURE_2D, 0);
2145 glDeleteTextures(1, &tmpTexture);
2149 f = fopen(filename, "w+");
2151 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2152 return WINED3DERR_INVALIDCALL;
2154 /* Save the data out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha channel */
2155 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2170 fwrite(&width,2,1,f);
2172 fwrite(&height,2,1,f);
2177 /* 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 */
2179 textureRow = allocatedMemory + (width * (height - 1) *4);
2181 textureRow = allocatedMemory;
2182 for (y = 0 ; y < height; y++) {
2183 for (i = 0; i < width; i++) {
2184 color = *((DWORD*)textureRow);
2185 fputc((color >> 16) & 0xFF, f); /* B */
2186 fputc((color >> 8) & 0xFF, f); /* G */
2187 fputc((color >> 0) & 0xFF, f); /* R */
2188 fputc((color >> 24) & 0xFF, f); /* A */
2191 /* take two rows of the pointer to the texture memory */
2193 (textureRow-= width << 3);
2196 TRACE("Closing file\n");
2200 IWineD3DSwapChain_Release(swapChain);
2202 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2207 * Slightly inefficient way to handle multiple dirty rects but it works :)
2209 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2210 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2211 IWineD3DBaseTexture *baseTexture = NULL;
2212 if (!(This->Flags & SFLAG_INSYSMEM) && (This->Flags & SFLAG_INTEXTURE))
2213 surface_download_data(This);
2215 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
2216 if (NULL != pDirtyRect) {
2217 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2218 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2219 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2220 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2222 This->dirtyRect.left = 0;
2223 This->dirtyRect.top = 0;
2224 This->dirtyRect.right = This->currentDesc.Width;
2225 This->dirtyRect.bottom = This->currentDesc.Height;
2227 TRACE("(%p) : Dirty: yes, Rect:(%d,%d,%d,%d)\n", This, This->dirtyRect.left,
2228 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2229 /* if the container is a basetexture then mark it dirty. */
2230 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2231 TRACE("Passing to container\n");
2232 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2233 IWineD3DBaseTexture_Release(baseTexture);
2238 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2239 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2241 TRACE("This %p, container %p\n", This, container);
2243 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2245 TRACE("Setting container to %p from %p\n", container, This->container);
2246 This->container = container;
2251 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2252 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2253 const GlPixelFormatDesc *glDesc;
2254 const StaticPixelFormatDesc *formatEntry = getFormatDescEntry(format, &GLINFO_LOCATION, &glDesc);
2256 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2257 FIXME("(%p) : The format of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2258 return WINED3DERR_INVALIDCALL;
2261 TRACE("(%p) : Setting texture format to (%d,%s)\n", This, format, debug_d3dformat(format));
2262 if (format == WINED3DFMT_UNKNOWN) {
2263 This->resource.size = 0;
2264 } else if (format == WINED3DFMT_DXT1) {
2265 /* DXT1 is half byte per pixel */
2266 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2268 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2269 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2270 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2272 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
2273 This->resource.size = ((This->pow2Width * formatEntry->bpp) + alignment - 1) & ~(alignment - 1);
2274 This->resource.size *= This->pow2Height;
2278 /* Setup some glformat defaults */
2279 This->glDescription.glFormat = glDesc->glFormat;
2280 This->glDescription.glFormatInternal = glDesc->glInternal;
2281 This->glDescription.glType = glDesc->glType;
2283 if (format != WINED3DFMT_UNKNOWN) {
2284 This->bytesPerPixel = formatEntry->bpp;
2286 This->bytesPerPixel = 0;
2289 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2290 This->Flags &= ~SFLAG_ALLOCATED;
2292 This->resource.format = format;
2294 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);
2299 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2300 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2302 /* Render targets depend on their hdc, and we can't create an hdc on a user pointer */
2303 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2304 ERR("Not supported on render targets\n");
2305 return WINED3DERR_INVALIDCALL;
2308 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2309 WARN("Surface is locked or the HDC is in use\n");
2310 return WINED3DERR_INVALIDCALL;
2313 if(Mem && Mem != This->resource.allocatedMemory) {
2314 void *release = NULL;
2316 /* Do I have to copy the old surface content? */
2317 if(This->Flags & SFLAG_DIBSECTION) {
2318 /* Release the DC. No need to hold the critical section for the update
2319 * Thread because this thread runs only on front buffers, but this method
2320 * fails for render targets in the check above.
2322 SelectObject(This->hDC, This->dib.holdbitmap);
2323 DeleteDC(This->hDC);
2324 /* Release the DIB section */
2325 DeleteObject(This->dib.DIBsection);
2326 This->dib.bitmap_data = NULL;
2327 This->resource.allocatedMemory = NULL;
2329 This->Flags &= ~SFLAG_DIBSECTION;
2330 } else if(!(This->Flags & SFLAG_USERPTR)) {
2331 release = This->resource.allocatedMemory;
2333 This->resource.allocatedMemory = Mem;
2334 This->Flags |= SFLAG_USERPTR | SFLAG_INSYSMEM;
2336 /* Now the surface memory is most up do date. Invalidate drawable and texture */
2337 This->Flags &= ~(SFLAG_INDRAWABLE | SFLAG_INTEXTURE);
2339 /* For client textures opengl has to be notified */
2340 if(This->Flags & SFLAG_CLIENT) {
2341 This->Flags &= ~SFLAG_ALLOCATED;
2342 IWineD3DSurface_PreLoad(iface);
2343 /* And hope that the app behaves correctly and did not free the old surface memory before setting a new pointer */
2346 /* Now free the old memory if any */
2347 HeapFree(GetProcessHeap(), 0, release);
2348 } else if(This->Flags & SFLAG_USERPTR) {
2349 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2350 This->resource.allocatedMemory = NULL;
2351 This->Flags &= ~SFLAG_USERPTR;
2353 if(This->Flags & SFLAG_CLIENT) {
2354 This->Flags &= ~SFLAG_ALLOCATED;
2355 /* This respecifies an empty texture and opengl knows that the old memory is gone */
2356 IWineD3DSurface_PreLoad(iface);
2362 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2363 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2364 IWineD3DSwapChainImpl *swapchain = NULL;
2366 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2368 /* Flipping is only supported on RenderTargets */
2369 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return WINEDDERR_NOTFLIPPABLE;
2372 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2373 * FIXME("(%p) Target override is not supported by now\n", This);
2374 * Additionally, it isn't really possible to support triple-buffering
2375 * properly on opengl at all
2379 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **) &swapchain);
2381 ERR("Flipped surface is not on a swapchain\n");
2382 return WINEDDERR_NOTFLIPPABLE;
2385 /* Just overwrite the swapchain presentation interval. This is ok because only ddraw apps can call Flip,
2386 * and only d3d8 and d3d9 apps specify the presentation interval
2388 if((Flags & (WINEDDFLIP_NOVSYNC | WINEDDFLIP_INTERVAL2 | WINEDDFLIP_INTERVAL3 | WINEDDFLIP_INTERVAL4)) == 0) {
2389 /* Most common case first to avoid wasting time on all the other cases */
2390 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_ONE;
2391 } else if(Flags & WINEDDFLIP_NOVSYNC) {
2392 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
2393 } else if(Flags & WINEDDFLIP_INTERVAL2) {
2394 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_TWO;
2395 } else if(Flags & WINEDDFLIP_INTERVAL3) {
2396 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_THREE;
2398 swapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_FOUR;
2401 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2402 hr = IWineD3DSwapChain_Present((IWineD3DSwapChain *) swapchain, NULL, NULL, 0, NULL, 0);
2403 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2407 /* Does a direct frame buffer -> texture copy. Stretching is done
2408 * with single pixel copy calls
2410 static inline void fb_copy_to_texture_direct(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter) {
2411 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2414 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2418 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2419 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2421 /* Bind the target texture */
2422 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2423 checkGLcall("glBindTexture");
2425 glReadBuffer(myDevice->offscreenBuffer);
2427 GLenum buffer = surface_get_gl_buffer(SrcSurface, (IWineD3DSwapChain *)swapchain);
2428 glReadBuffer(buffer);
2430 checkGLcall("glReadBuffer");
2432 xrel = (float) (srect->x2 - srect->x1) / (float) (drect->x2 - drect->x1);
2433 yrel = (float) (srect->y2 - srect->y1) / (float) (drect->y2 - drect->y1);
2435 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2436 FIXME("Doing a pixel by pixel copy from the framebuffer to a texture, expect major performance issues\n");
2438 if(Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) {
2439 ERR("Texture filtering not supported in direct blit\n");
2441 } else if((Filter != WINED3DTEXF_NONE && Filter != WINED3DTEXF_POINT) && ((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2442 ERR("Texture filtering not supported in direct blit\n");
2446 !((xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) &&
2447 !((yrel - 1.0 < -eps) || (yrel - 1.0 > eps))) {
2448 /* Upside down copy without stretching is nice, one glCopyTexSubImage call will do */
2450 glCopyTexSubImage2D(This->glDescription.target,
2451 This->glDescription.level,
2452 drect->x1, drect->y1, /* xoffset, yoffset */
2453 srect->x1, Src->currentDesc.Height - srect->y2,
2454 drect->x2 - drect->x1, drect->y2 - drect->y1);
2456 UINT yoffset = Src->currentDesc.Height - srect->y1 + drect->y1 - 1;
2457 /* I have to process this row by row to swap the image,
2458 * otherwise it would be upside down, so stretching in y direction
2459 * doesn't cost extra time
2461 * However, stretching in x direction can be avoided if not necessary
2463 for(row = drect->y1; row < drect->y2; row++) {
2464 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2465 /* Well, that stuff works, but it's very slow.
2466 * find a better way instead
2470 for(col = drect->x1; col < drect->x2; col++) {
2471 glCopyTexSubImage2D(This->glDescription.target,
2472 This->glDescription.level,
2473 drect->x1 + col, row, /* xoffset, yoffset */
2474 srect->x1 + col * xrel, yoffset - (int) (row * yrel),
2478 glCopyTexSubImage2D(This->glDescription.target,
2479 This->glDescription.level,
2480 drect->x1, row, /* xoffset, yoffset */
2481 srect->x1, yoffset - (int) (row * yrel),
2482 drect->x2-drect->x1, 1);
2487 vcheckGLcall("glCopyTexSubImage2D");
2491 /* Uses the hardware to stretch and flip the image */
2492 static inline void fb_copy_to_texture_hwstretch(IWineD3DSurfaceImpl *This, IWineD3DSurface *SrcSurface, IWineD3DSwapChainImpl *swapchain, WINED3DRECT *srect, WINED3DRECT *drect, BOOL upsidedown, WINED3DTEXTUREFILTERTYPE Filter) {
2493 GLuint src, backup = 0;
2494 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2495 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2496 float left, right, top, bottom; /* Texture coordinates */
2497 UINT fbwidth = Src->currentDesc.Width;
2498 UINT fbheight = Src->currentDesc.Height;
2499 GLenum drawBuffer = GL_BACK;
2501 TRACE("Using hwstretch blit\n");
2502 /* Activate the Proper context for reading from the source surface, set it up for blitting */
2504 ActivateContext(myDevice, SrcSurface, CTXUSAGE_BLIT);
2505 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2507 /* Try to use an aux buffer for drawing the rectangle. This way it doesn't need restoring.
2508 * This way we don't have to wait for the 2nd readback to finish to leave this function.
2510 if(GL_LIMITS(aux_buffers) >= 2) {
2511 /* Got more than one aux buffer? Use the 2nd aux buffer */
2512 drawBuffer = GL_AUX1;
2513 } else if((swapchain || myDevice->offscreenBuffer == GL_BACK) && GL_LIMITS(aux_buffers) >= 1) {
2514 /* Only one aux buffer, but it isn't used (Onscreen rendering, or non-aux orm)? Use it! */
2515 drawBuffer = GL_AUX0;
2518 if(!swapchain && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
2519 glGenTextures(1, &backup);
2520 checkGLcall("glGenTextures\n");
2521 glBindTexture(GL_TEXTURE_2D, backup);
2522 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2524 /* Backup the back buffer and copy the source buffer into a texture to draw an upside down stretched quad. If
2525 * we are reading from the back buffer, the backup can be used as source texture
2527 if(Src->glDescription.textureName == 0) {
2528 /* Get it a description */
2529 IWineD3DSurface_PreLoad(SrcSurface);
2531 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2532 checkGLcall("glBindTexture(Src->glDescription.target, Src->glDescription.textureName)");
2534 /* For now invalidate the texture copy of the back buffer. Drawable and sysmem copy are untouched */
2535 Src->Flags &= ~SFLAG_INTEXTURE;
2538 glReadBuffer(GL_BACK);
2539 checkGLcall("glReadBuffer(GL_BACK)");
2541 /* TODO: Only back up the part that will be overwritten */
2542 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2543 0, 0 /* read offsets */,
2548 checkGLcall("glCopyTexSubImage2D");
2550 /* No issue with overriding these - the sampler is dirty due to blit usage */
2551 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2552 stateLookup[WINELOOKUP_MAGFILTER][Filter - minLookup[WINELOOKUP_MAGFILTER]]);
2553 checkGLcall("glTexParameteri");
2554 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2555 minMipLookup[Filter][WINED3DTEXF_NONE]);
2556 checkGLcall("glTexParameteri");
2558 if(!swapchain || (IWineD3DSurface *) Src == swapchain->backBuffer[0]) {
2559 src = backup ? backup : Src->glDescription.textureName;
2561 glReadBuffer(GL_FRONT);
2562 checkGLcall("glReadBuffer(GL_FRONT)");
2564 glGenTextures(1, &src);
2565 checkGLcall("glGenTextures(1, &src)");
2566 glBindTexture(GL_TEXTURE_2D, src);
2567 checkGLcall("glBindTexture(GL_TEXTURE_2D, src)");
2569 /* TODO: Only copy the part that will be read. Use srect->x1, srect->y2 as origin, but with the width watch
2570 * out for power of 2 sizes
2572 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Src->pow2Width, Src->pow2Height, 0,
2573 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2574 checkGLcall("glTexImage2D");
2575 glCopyTexSubImage2D(GL_TEXTURE_2D, 0,
2576 0, 0 /* read offsets */,
2581 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
2582 checkGLcall("glTexParameteri");
2583 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
2584 checkGLcall("glTexParameteri");
2586 glReadBuffer(GL_BACK);
2587 checkGLcall("glReadBuffer(GL_BACK)");
2589 checkGLcall("glEnd and previous");
2591 left = (float) srect->x1 / (float) Src->pow2Width;
2592 right = (float) srect->x2 / (float) Src->pow2Width;
2595 top = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2596 bottom = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2598 top = (float) (Src->currentDesc.Height - srect->y2) / (float) Src->pow2Height;
2599 bottom = (float) (Src->currentDesc.Height - srect->y1) / (float) Src->pow2Height;
2602 /* draw the source texture stretched and upside down. The correct surface is bound already */
2603 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2604 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2606 glDrawBuffer(drawBuffer);
2607 glReadBuffer(drawBuffer);
2611 glTexCoord2f(left, bottom);
2612 glVertex2i(0, fbheight);
2615 glTexCoord2f(left, top);
2616 glVertex2i(0, fbheight - drect->y2 - drect->y1);
2619 glTexCoord2f(right, top);
2620 glVertex2i(drect->x2 - drect->x1, fbheight - drect->y2 - drect->y1);
2623 glTexCoord2f(right, bottom);
2624 glVertex2i(drect->x2 - drect->x1, fbheight);
2626 checkGLcall("glEnd and previous");
2628 /* Now read the stretched and upside down image into the destination texture */
2629 glBindTexture(This->glDescription.target, This->glDescription.textureName);
2630 checkGLcall("glBindTexture");
2631 glCopyTexSubImage2D(This->glDescription.target,
2633 drect->x1, drect->y1, /* xoffset, yoffset */
2634 0, 0, /* We blitted the image to the origin */
2635 drect->x2 - drect->x1, drect->y2 - drect->y1);
2636 checkGLcall("glCopyTexSubImage2D");
2638 /* Write the back buffer backup back */
2639 glBindTexture(GL_TEXTURE_2D, backup ? backup : Src->glDescription.textureName);
2640 checkGLcall("glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName)");
2642 if(drawBuffer == GL_BACK) {
2645 glTexCoord2f(0.0, (float) fbheight / (float) Src->pow2Height);
2649 glTexCoord2f(0.0, 0.0);
2650 glVertex2i(0, fbheight);
2653 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, 0.0);
2654 glVertex2i(fbwidth, Src->currentDesc.Height);
2657 glTexCoord2f((float) fbwidth / (float) Src->pow2Width, (float) fbheight / (float) Src->pow2Height);
2658 glVertex2i(fbwidth, 0);
2661 /* Restore the old draw buffer */
2662 glDrawBuffer(GL_BACK);
2666 if(src != Src->glDescription.textureName && src != backup) {
2667 glDeleteTextures(1, &src);
2668 checkGLcall("glDeleteTextures(1, &src)");
2671 glDeleteTextures(1, &backup);
2672 checkGLcall("glDeleteTextures(1, &backup)");
2677 /* Not called from the VTable */
2678 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
2680 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2681 IWineD3DSwapChainImpl *srcSwapchain = NULL, *dstSwapchain = NULL;
2682 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2684 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2686 /* Get the swapchain. One of the surfaces has to be a primary surface */
2687 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&dstSwapchain);
2688 if(dstSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) dstSwapchain);
2690 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&srcSwapchain);
2691 if(srcSwapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) srcSwapchain);
2694 /* Early sort out of cases where no render target is used */
2695 if(!dstSwapchain && !srcSwapchain &&
2696 SrcSurface != myDevice->render_targets[0] && This != (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
2697 TRACE("No surface is render target, not using hardware blit. Src = %p, dst = %p\n", Src, This);
2698 return WINED3DERR_INVALIDCALL;
2701 /* No destination color keying supported */
2702 if(Flags & (WINEDDBLT_KEYDEST | WINEDDBLT_KEYDESTOVERRIDE)) {
2703 /* Can we support that with glBlendFunc if blitting to the frame buffer? */
2704 TRACE("Destination color key not supported in accelerated Blit, falling back to software\n");
2705 return WINED3DERR_INVALIDCALL;
2709 rect.x1 = DestRect->left;
2710 rect.y1 = DestRect->top;
2711 rect.x2 = DestRect->right;
2712 rect.y2 = DestRect->bottom;
2716 rect.x2 = This->currentDesc.Width;
2717 rect.y2 = This->currentDesc.Height;
2720 /* The only case where both surfaces on a swapchain are supported is a back buffer -> front buffer blit on the same swapchain */
2721 if(dstSwapchain && dstSwapchain == srcSwapchain && dstSwapchain->backBuffer &&
2722 ((IWineD3DSurface *) This == dstSwapchain->frontBuffer) && SrcSurface == dstSwapchain->backBuffer[0]) {
2723 /* Half-life does a Blt from the back buffer to the front buffer,
2724 * Full surface size, no flags... Use present instead
2726 * This path will only be entered for d3d7 and ddraw apps, because d3d8/9 offer no way to blit TO the front buffer
2729 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2733 TRACE("Looking if a Present can be done...\n");
2734 /* Source Rectangle must be full surface */
2736 if(SrcRect->left != 0 || SrcRect->top != 0 ||
2737 SrcRect->right != Src->currentDesc.Width || SrcRect->bottom != Src->currentDesc.Height) {
2738 TRACE("No, Source rectangle doesn't match\n");
2744 mySrcRect.right = Src->currentDesc.Width;
2745 mySrcRect.bottom = Src->currentDesc.Height;
2747 /* No stretching may occur */
2748 if(mySrcRect.right != rect.x2 - rect.x1 ||
2749 mySrcRect.bottom != rect.y2 - rect.y1) {
2750 TRACE("No, stretching is done\n");
2754 /* Destination must be full surface or match the clipping rectangle */
2755 if(This->clipper && ((IWineD3DClipperImpl *) This->clipper)->hWnd)
2759 GetClientRect(((IWineD3DClipperImpl *) This->clipper)->hWnd, &cliprect);
2764 MapWindowPoints(GetDesktopWindow(), ((IWineD3DClipperImpl *) This->clipper)->hWnd,
2767 if(pos[0].x != cliprect.left || pos[0].y != cliprect.top ||
2768 pos[1].x != cliprect.right || pos[1].y != cliprect.bottom)
2770 TRACE("No, dest rectangle doesn't match(clipper)\n");
2771 TRACE("Clip rect at (%d,%d)-(%d,%d)\n", cliprect.left, cliprect.top, cliprect.right, cliprect.bottom);
2772 TRACE("Blt dest: (%d,%d)-(%d,%d)\n", rect.x1, rect.y1, rect.x2, rect.y2);
2778 if(rect.x1 != 0 || rect.y1 != 0 ||
2779 rect.x2 != This->currentDesc.Width || rect.y2 != This->currentDesc.Height) {
2780 TRACE("No, dest rectangle doesn't match(surface size)\n");
2787 /* These flags are unimportant for the flag check, remove them */
2788 if((Flags & ~(WINEDDBLT_DONOTWAIT | WINEDDBLT_WAIT)) == 0) {
2789 WINED3DSWAPEFFECT orig_swap = dstSwapchain->presentParms.SwapEffect;
2791 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2792 * take very long, while a flip is fast.
2793 * This applies to Half-Life, which does such Blts every time it finished
2794 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2795 * menu. This is also used by all apps when they do windowed rendering
2797 * The problem is that flipping is not really the same as copying. After a
2798 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2799 * untouched. Therefore it's necessary to override the swap effect
2800 * and to set it back after the flip.
2802 * Windowed Direct3D < 7 apps do the same. The D3D7 sdk demos are nice
2806 dstSwapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2807 dstSwapchain->presentParms.PresentationInterval = WINED3DPRESENT_INTERVAL_IMMEDIATE;
2809 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2810 IWineD3DSwapChain_Present((IWineD3DSwapChain *) dstSwapchain, NULL, NULL, 0, NULL, 0);
2812 dstSwapchain->presentParms.SwapEffect = orig_swap;
2819 TRACE("Unsupported blit between buffers on the same swapchain\n");
2820 return WINED3DERR_INVALIDCALL;
2821 } else if((dstSwapchain || This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) &&
2822 (srcSwapchain || SrcSurface == myDevice->render_targets[0]) ) {
2823 ERR("Can't perform hardware blit between 2 different swapchains, falling back to software\n");
2824 return WINED3DERR_INVALIDCALL;
2827 if(srcSwapchain || SrcSurface == myDevice->render_targets[0]) {
2828 /* Blit from render target to texture */
2830 BOOL upsideDown, stretchx;
2832 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
2833 TRACE("Color keying not supported by frame buffer to texture blit\n");
2834 return WINED3DERR_INVALIDCALL;
2835 /* Destination color key is checked above */
2838 /* Make sure that the top pixel is always above the bottom pixel, and keep a separate upside down flag
2839 * glCopyTexSubImage is a bit picky about the parameters we pass to it
2842 if(SrcRect->top < SrcRect->bottom) {
2843 srect.y1 = SrcRect->top;
2844 srect.y2 = SrcRect->bottom;
2847 srect.y1 = SrcRect->bottom;
2848 srect.y2 = SrcRect->top;
2851 srect.x1 = SrcRect->left;
2852 srect.x2 = SrcRect->right;
2856 srect.x2 = Src->currentDesc.Width;
2857 srect.y2 = Src->currentDesc.Height;
2860 if(rect.x1 > rect.x2) {
2864 upsideDown = !upsideDown;
2867 TRACE("Reading from an offscreen target\n");
2868 upsideDown = !upsideDown;
2871 if(rect.x2 - rect.x1 != srect.x2 - srect.x1) {
2877 /* Blt is a pretty powerful call, while glCopyTexSubImage2D is not. glCopyTexSubImage cannot
2878 * flip the image nor scale it.
2880 * -> If the app asks for a unscaled, upside down copy, just perform one glCopyTexSubImage2D call
2881 * -> If the app wants a image width an unscaled width, copy it line per line
2882 * -> If the app wants a image that is scaled on the x axis, and the destination rectangle is smaller
2883 * than the frame buffer, draw an upside down scaled image onto the fb, read it back and restore the
2884 * back buffer. This is slower than reading line per line, thus not used for flipping
2885 * -> If the app wants a scaled image with a dest rect that is bigger than the fb, it has to be copied
2888 * If EXT_framebuffer_blit is supported that can be used instead. Note that EXT_framebuffer_blit implies
2889 * FBO support, so it doesn't really make sense to try and make it work with different offscreen rendering
2892 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO && GL_SUPPORT(EXT_FRAMEBUFFER_BLIT)) {
2893 stretch_rect_fbo((IWineD3DDevice *)myDevice, SrcSurface, &srect,
2894 (IWineD3DSurface *)This, &rect, Filter, upsideDown);
2895 } else if((!stretchx) || rect.x2 - rect.x1 > Src->currentDesc.Width ||
2896 rect.y2 - rect.y1 > Src->currentDesc.Height) {
2897 TRACE("No stretching in x direction, using direct framebuffer -> texture copy\n");
2898 fb_copy_to_texture_direct(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown, Filter);
2900 TRACE("Using hardware stretching to flip / stretch the texture\n");
2901 fb_copy_to_texture_hwstretch(This, SrcSurface, srcSwapchain, &srect, &rect, upsideDown, Filter);
2904 if(!(This->Flags & SFLAG_DONOTFREE)) {
2905 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2906 This->resource.allocatedMemory = NULL;
2908 This->Flags &= ~SFLAG_INSYSMEM;
2910 /* The texture is now most up to date - If the surface is a render target and has a drawable, this
2911 * path is never entered
2913 This->Flags |= SFLAG_INTEXTURE;
2917 /* Blit from offscreen surface to render target */
2918 float glTexCoord[4];
2919 DWORD oldCKeyFlags = Src->CKeyFlags;
2920 WINEDDCOLORKEY oldBltCKey = This->SrcBltCKey;
2921 RECT SourceRectangle;
2923 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2926 SourceRectangle.left = SrcRect->left;
2927 SourceRectangle.right = SrcRect->right;
2928 SourceRectangle.top = SrcRect->top;
2929 SourceRectangle.bottom = SrcRect->bottom;
2931 SourceRectangle.left = 0;
2932 SourceRectangle.right = Src->currentDesc.Width;
2933 SourceRectangle.top = 0;
2934 SourceRectangle.bottom = Src->currentDesc.Height;
2937 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2938 /* Fall back to software */
2939 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2940 SourceRectangle.left, SourceRectangle.top,
2941 SourceRectangle.right, SourceRectangle.bottom);
2942 return WINED3DERR_INVALIDCALL;
2945 /* Color keying: Check if we have to do a color keyed blt,
2946 * and if not check if a color key is activated.
2948 * Just modify the color keying parameters in the surface and restore them afterwards
2949 * The surface keeps track of the color key last used to load the opengl surface.
2950 * PreLoad will catch the change to the flags and color key and reload if necessary.
2952 if(Flags & WINEDDBLT_KEYSRC) {
2953 /* Use color key from surface */
2954 } else if(Flags & WINEDDBLT_KEYSRCOVERRIDE) {
2955 /* Use color key from DDBltFx */
2956 Src->CKeyFlags |= WINEDDSD_CKSRCBLT;
2957 This->SrcBltCKey = DDBltFx->ddckSrcColorkey;
2959 /* Do not use color key */
2960 Src->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
2963 /* Now load the surface */
2964 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2968 /* Activate the destination context, set it up for blitting */
2969 ActivateContext(myDevice, (IWineD3DSurface *) This, CTXUSAGE_BLIT);
2972 TRACE("Drawing to offscreen buffer\n");
2973 glDrawBuffer(myDevice->offscreenBuffer);
2974 checkGLcall("glDrawBuffer");
2976 GLenum buffer = surface_get_gl_buffer((IWineD3DSurface *)This, (IWineD3DSwapChain *)dstSwapchain);
2977 TRACE("Drawing to %#x buffer\n", buffer);
2978 glDrawBuffer(buffer);
2979 checkGLcall("glDrawBuffer");
2982 /* Bind the texture */
2983 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2984 checkGLcall("glBindTexture");
2986 /* Filtering for StretchRect */
2987 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2988 stateLookup[WINELOOKUP_MAGFILTER][Filter - minLookup[WINELOOKUP_MAGFILTER]]);
2989 checkGLcall("glTexParameteri");
2990 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2991 minMipLookup[Filter][WINED3DTEXF_NONE]);
2992 checkGLcall("glTexParameteri");
2993 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2994 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2995 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2996 checkGLcall("glTexEnvi");
2998 /* This is for color keying */
2999 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3000 glEnable(GL_ALPHA_TEST);
3001 checkGLcall("glEnable GL_ALPHA_TEST");
3002 glAlphaFunc(GL_NOTEQUAL, 0.0);
3003 checkGLcall("glAlphaFunc\n");
3005 glDisable(GL_ALPHA_TEST);
3006 checkGLcall("glDisable GL_ALPHA_TEST");
3009 /* Draw a textured quad
3013 glColor3d(1.0f, 1.0f, 1.0f);
3014 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
3019 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
3020 glVertex3f(rect.x1, rect.y2, 0.0);
3022 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
3027 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
3032 checkGLcall("glEnd");
3034 if(Flags & (WINEDDBLT_KEYSRC | WINEDDBLT_KEYSRCOVERRIDE)) {
3035 glDisable(GL_ALPHA_TEST);
3036 checkGLcall("glDisable(GL_ALPHA_TEST)");
3039 /* Unbind the texture */
3040 glBindTexture(GL_TEXTURE_2D, 0);
3041 checkGLcall("glEnable glBindTexture");
3043 /* The draw buffer should only need to be restored if we were drawing to the front buffer, and there is a back buffer.
3044 * otherwise the context manager should choose between GL_BACK / offscreenDrawBuffer
3046 if(dstSwapchain && This == (IWineD3DSurfaceImpl *) dstSwapchain->frontBuffer && dstSwapchain->backBuffer) {
3047 glDrawBuffer(GL_BACK);
3048 checkGLcall("glDrawBuffer");
3050 /* Restore the color key parameters */
3051 Src->CKeyFlags = oldCKeyFlags;
3052 This->SrcBltCKey = oldBltCKey;
3056 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
3057 This->Flags &= ~SFLAG_INSYSMEM;
3058 /* The surface is now in the drawable. On onscreen surfaces or without fbos the texture
3061 if(dstSwapchain || wined3d_settings.offscreen_rendering_mode != ORM_FBO) {
3062 This->Flags |= SFLAG_INDRAWABLE;
3063 This->Flags &= ~SFLAG_INTEXTURE;
3065 This->Flags |= SFLAG_INTEXTURE;
3070 /* Source-Less Blit to render target */
3071 if (Flags & WINEDDBLT_COLORFILL) {
3072 /* This is easy to handle for the D3D Device... */
3075 TRACE("Colorfill\n");
3077 /* The color as given in the Blt function is in the format of the frame-buffer...
3078 * 'clear' expect it in ARGB format => we need to do some conversion :-)
3080 if (This->resource.format == WINED3DFMT_P8) {
3081 if (This->palette) {
3082 color = ((0xFF000000) |
3083 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
3084 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
3085 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
3090 else if (This->resource.format == WINED3DFMT_R5G6B5) {
3091 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
3094 color = ((0xFF000000) |
3095 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
3096 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
3097 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
3100 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
3101 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
3102 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
3104 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
3105 color = DDBltFx->u5.dwFillColor;
3108 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
3109 return WINED3DERR_INVALIDCALL;
3112 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
3113 if(dstSwapchain && dstSwapchain->backBuffer && This == (IWineD3DSurfaceImpl*) dstSwapchain->backBuffer[0]) {
3114 glDrawBuffer(GL_BACK);
3115 checkGLcall("glDrawBuffer(GL_BACK)");
3116 } else if (dstSwapchain && This == (IWineD3DSurfaceImpl*) dstSwapchain->frontBuffer) {
3117 glDrawBuffer(GL_FRONT);
3118 checkGLcall("glDrawBuffer(GL_FRONT)");
3119 } else if(This == (IWineD3DSurfaceImpl *) myDevice->render_targets[0]) {
3120 glDrawBuffer(myDevice->offscreenBuffer);
3121 checkGLcall("glDrawBuffer(myDevice->offscreenBuffer3)");
3123 TRACE("Surface is higher back buffer, falling back to software\n");
3124 return WINED3DERR_INVALIDCALL;
3127 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
3129 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
3130 1 /* Number of rectangles */,
3132 WINED3DCLEAR_TARGET,
3137 /* Restore the original draw buffer */
3139 glDrawBuffer(myDevice->offscreenBuffer);
3140 } else if(dstSwapchain->backBuffer && dstSwapchain->backBuffer[0]) {
3141 glDrawBuffer(GL_BACK);
3143 vcheckGLcall("glDrawBuffer");
3149 /* Default: Fall back to the generic blt. Not an error, a TRACE is enough */
3150 TRACE("Didn't find any usable render target setup for hw blit, falling back to software\n");
3151 return WINED3DERR_INVALIDCALL;
3154 static HRESULT WINAPI IWineD3DSurfaceImpl_BltZ(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx)
3156 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3158 if (Flags & WINEDDBLT_DEPTHFILL)
3159 return IWineD3DDevice_Clear((IWineD3DDevice *) myDevice,
3160 DestRect == NULL ? 0 : 1,
3161 (WINED3DRECT *) DestRect,
3162 WINED3DCLEAR_ZBUFFER,
3164 (float) DDBltFx->u5.dwFillDepth / (float) MAXDWORD,
3167 FIXME("(%p): Unsupp depthstencil blit\n", This);
3168 return WINED3DERR_INVALIDCALL;
3171 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, WINEDDBLTFX *DDBltFx, WINED3DTEXTUREFILTERTYPE Filter) {
3172 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3173 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
3174 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3175 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
3176 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
3178 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair,
3179 * except depth blits, which seem to work
3181 if(iface == myDevice->stencilBufferTarget || (SrcSurface && SrcSurface == myDevice->stencilBufferTarget)) {
3182 if(myDevice->inScene && !(Flags & WINEDDBLT_DEPTHFILL)) {
3183 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3184 return WINED3DERR_INVALIDCALL;
3185 } else if(IWineD3DSurfaceImpl_BltZ(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) {
3186 TRACE("Z Blit override handled the blit\n");
3191 /* Special cases for RenderTargets */
3192 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3193 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
3194 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter) == WINED3D_OK) return WINED3D_OK;
3197 /* For the rest call the X11 surface implementation.
3198 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
3199 * other Blts are rather rare
3201 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx, Filter);
3204 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
3205 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
3206 TRACE("(%p)->(%x)\n", This, Flags);
3210 case WINEDDGBS_CANBLT:
3211 case WINEDDGBS_ISBLTDONE:
3215 return WINED3DERR_INVALIDCALL;
3219 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
3220 /* XXX: DDERR_INVALIDSURFACETYPE */
3222 TRACE("(%p)->(%08x)\n",iface,Flags);
3224 case WINEDDGFS_CANFLIP:
3225 case WINEDDGFS_ISFLIPDONE:
3229 return WINED3DERR_INVALIDCALL;
3233 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
3234 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3235 TRACE("(%p)\n", This);
3237 /* D3D8 and 9 loose full devices, ddraw only surfaces */
3238 return This->Flags & SFLAG_LOST ? WINED3DERR_DEVICELOST : WINED3D_OK;
3241 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
3242 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3243 TRACE("(%p)\n", This);
3245 /* So far we don't lose anything :) */
3246 This->Flags &= ~SFLAG_LOST;
3250 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
3251 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3252 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
3253 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
3254 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
3256 if(myDevice->inScene &&
3257 (iface == myDevice->stencilBufferTarget ||
3258 (Source && Source == myDevice->stencilBufferTarget))) {
3259 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
3260 return WINED3DERR_INVALIDCALL;
3263 /* Special cases for RenderTargets */
3264 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
3265 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
3267 RECT SrcRect, DstRect;
3271 SrcRect.left = rsrc->left;
3272 SrcRect.top= rsrc->top;
3273 SrcRect.bottom = rsrc->bottom;
3274 SrcRect.right = rsrc->right;
3278 SrcRect.right = srcImpl->currentDesc.Width;
3279 SrcRect.bottom = srcImpl->currentDesc.Height;
3282 DstRect.left = dstx;
3284 DstRect.right = dstx + SrcRect.right - SrcRect.left;
3285 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
3287 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
3288 if(trans & WINEDDBLTFAST_SRCCOLORKEY)
3289 Flags |= WINEDDBLT_KEYSRC;
3290 if(trans & WINEDDBLTFAST_DESTCOLORKEY)
3291 Flags |= WINEDDBLT_KEYDEST;
3292 if(trans & WINEDDBLTFAST_WAIT)
3293 Flags |= WINEDDBLT_WAIT;
3294 if(trans & WINEDDBLTFAST_DONOTWAIT)
3295 Flags |= WINEDDBLT_DONOTWAIT;
3297 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL, WINED3DTEXF_POINT) == WINED3D_OK) return WINED3D_OK;
3301 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
3304 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
3305 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3306 TRACE("(%p)->(%p)\n", This, Pal);
3308 *Pal = (IWineD3DPalette *) This->palette;
3312 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
3313 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3315 IWineD3DPaletteImpl *pal = This->palette;
3317 TRACE("(%p)\n", This);
3319 if(This->resource.format == WINED3DFMT_P8 ||
3320 This->resource.format == WINED3DFMT_A8P8)
3322 if(!This->Flags & SFLAG_INSYSMEM) {
3323 FIXME("Palette changed with surface that does not have an up to date system memory copy\n");
3325 TRACE("Dirtifying surface\n");
3326 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INDRAWABLE);
3329 if(This->Flags & SFLAG_DIBSECTION) {
3330 TRACE("(%p): Updating the hdc's palette\n", This);
3331 for (n=0; n<256; n++) {
3333 col[n].rgbRed = pal->palents[n].peRed;
3334 col[n].rgbGreen = pal->palents[n].peGreen;
3335 col[n].rgbBlue = pal->palents[n].peBlue;
3337 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3338 /* Use the default device palette */
3339 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
3340 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
3341 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
3343 col[n].rgbReserved = 0;
3345 SetDIBColorTable(This->hDC, 0, 256, col);
3351 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
3352 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3353 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
3354 TRACE("(%p)->(%p)\n", This, Pal);
3356 if(This->palette != NULL)
3357 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
3358 This->palette->Flags &= ~WINEDDPCAPS_PRIMARYSURFACE;
3360 if(PalImpl != NULL) {
3361 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3362 /* Set the device's main palette if the palette
3363 * wasn't a primary palette before
3365 if(!(PalImpl->Flags & WINEDDPCAPS_PRIMARYSURFACE)) {
3366 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
3369 for(i=0; i < 256; i++) {
3370 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
3374 (PalImpl)->Flags |= WINEDDPCAPS_PRIMARYSURFACE;
3377 This->palette = PalImpl;
3379 return IWineD3DSurface_RealizePalette(iface);
3382 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, WINEDDCOLORKEY *CKey) {
3383 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3384 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
3386 if ((Flags & WINEDDCKEY_COLORSPACE) != 0) {
3387 FIXME(" colorkey value not supported (%08x) !\n", Flags);
3388 return WINED3DERR_INVALIDCALL;
3391 /* Dirtify the surface, but only if a key was changed */
3393 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
3394 case WINEDDCKEY_DESTBLT:
3395 This->DestBltCKey = *CKey;
3396 This->CKeyFlags |= WINEDDSD_CKDESTBLT;
3399 case WINEDDCKEY_DESTOVERLAY:
3400 This->DestOverlayCKey = *CKey;
3401 This->CKeyFlags |= WINEDDSD_CKDESTOVERLAY;
3404 case WINEDDCKEY_SRCOVERLAY:
3405 This->SrcOverlayCKey = *CKey;
3406 This->CKeyFlags |= WINEDDSD_CKSRCOVERLAY;
3409 case WINEDDCKEY_SRCBLT:
3410 This->SrcBltCKey = *CKey;
3411 This->CKeyFlags |= WINEDDSD_CKSRCBLT;
3416 switch (Flags & ~WINEDDCKEY_COLORSPACE) {
3417 case WINEDDCKEY_DESTBLT:
3418 This->CKeyFlags &= ~WINEDDSD_CKDESTBLT;
3421 case WINEDDCKEY_DESTOVERLAY:
3422 This->CKeyFlags &= ~WINEDDSD_CKDESTOVERLAY;
3425 case WINEDDCKEY_SRCOVERLAY:
3426 This->CKeyFlags &= ~WINEDDSD_CKSRCOVERLAY;
3429 case WINEDDCKEY_SRCBLT:
3430 This->CKeyFlags &= ~WINEDDSD_CKSRCBLT;
3438 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3439 /** Check against the maximum texture sizes supported by the video card **/
3440 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3441 unsigned int pow2Width, pow2Height;
3442 const GlPixelFormatDesc *glDesc;
3443 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(This->resource.format, &GLINFO_LOCATION, &glDesc);
3445 /* Setup some glformat defaults */
3446 This->glDescription.glFormat = glDesc->glFormat;
3447 This->glDescription.glFormatInternal = glDesc->glInternal;
3448 This->glDescription.glType = glDesc->glType;
3450 This->glDescription.textureName = 0;
3451 This->glDescription.target = GL_TEXTURE_2D;
3453 /* Non-power2 support */
3454 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
3455 pow2Width = This->currentDesc.Width;
3456 pow2Height = This->currentDesc.Height;
3458 /* Find the nearest pow2 match */
3459 pow2Width = pow2Height = 1;
3460 while (pow2Width < This->currentDesc.Width) pow2Width <<= 1;
3461 while (pow2Height < This->currentDesc.Height) pow2Height <<= 1;
3463 This->pow2Width = pow2Width;
3464 This->pow2Height = pow2Height;
3466 if (pow2Width > This->currentDesc.Width || pow2Height > This->currentDesc.Height) {
3467 WINED3DFORMAT Format = This->resource.format;
3468 /** TODO: add support for non power two compressed textures **/
3469 if (Format == WINED3DFMT_DXT1 || Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3
3470 || Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
3471 FIXME("(%p) Compressed non-power-two textures are not supported w(%d) h(%d)\n",
3472 This, This->currentDesc.Width, This->currentDesc.Height);
3473 return WINED3DERR_NOTAVAILABLE;
3477 if(pow2Width != This->currentDesc.Width ||
3478 pow2Height != This->currentDesc.Height) {
3479 This->Flags |= SFLAG_NONPOW2;
3482 TRACE("%p\n", This);
3483 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3484 /* one of three options
3485 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)
3486 2: Set the texture to the maximum size (bad idea)
3487 3: WARN and return WINED3DERR_NOTAVAILABLE;
3488 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.
3490 WARN("(%p) Creating an oversized surface\n", This);
3491 This->Flags |= SFLAG_OVERSIZE;
3493 /* This will be initialized on the first blt */
3494 This->glRect.left = 0;
3495 This->glRect.top = 0;
3496 This->glRect.right = 0;
3497 This->glRect.bottom = 0;
3499 /* No oversize, gl rect is the full texture size */
3500 This->Flags &= ~SFLAG_OVERSIZE;
3501 This->glRect.left = 0;
3502 This->glRect.top = 0;
3503 This->glRect.right = This->pow2Width;
3504 This->glRect.bottom = This->pow2Height;
3507 if(This->resource.allocatedMemory == NULL) {
3508 /* Make sure memory exists from the start, and it is initialized properly. D3D initializes surfaces,
3509 * gl does not, so we need to upload zeroes to init the gl texture.
3511 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->resource.size + 4);
3513 This->Flags |= SFLAG_INSYSMEM;
3518 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3519 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3521 TRACE("(%p)\n", This);
3523 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3524 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3525 ie pitch = (width/4) * bytes per block */
3526 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3527 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3528 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3529 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3530 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3532 unsigned char alignment = This->resource.wineD3DDevice->surface_alignment;
3533 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3534 ret = (ret + alignment - 1) & ~(alignment - 1);
3536 TRACE("(%p) Returning %d\n", This, ret);
3540 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3541 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3543 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3545 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3547 TRACE("(%p): Not an overlay surface\n", This);
3548 return WINEDDERR_NOTAOVERLAYSURFACE;
3554 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3555 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3557 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3559 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3561 TRACE("(%p): Not an overlay surface\n", This);
3562 return WINEDDERR_NOTAOVERLAYSURFACE;
3568 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3569 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3570 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3572 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3574 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3576 TRACE("(%p): Not an overlay surface\n", This);
3577 return WINEDDERR_NOTAOVERLAYSURFACE;
3583 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3584 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3585 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3586 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3588 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3590 TRACE("(%p): Not an overlay surface\n", This);
3591 return WINEDDERR_NOTAOVERLAYSURFACE;
3597 HRESULT WINAPI IWineD3DSurfaceImpl_SetClipper(IWineD3DSurface *iface, IWineD3DClipper *clipper)
3599 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3600 TRACE("(%p)->(%p)\n", This, clipper);
3602 This->clipper = clipper;
3606 HRESULT WINAPI IWineD3DSurfaceImpl_GetClipper(IWineD3DSurface *iface, IWineD3DClipper **clipper)
3608 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3609 TRACE("(%p)->(%p)\n", This, clipper);
3611 *clipper = This->clipper;
3613 IWineD3DClipper_AddRef(*clipper);
3618 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3621 IWineD3DSurfaceImpl_QueryInterface,
3622 IWineD3DSurfaceImpl_AddRef,
3623 IWineD3DSurfaceImpl_Release,
3624 /* IWineD3DResource */
3625 IWineD3DSurfaceImpl_GetParent,
3626 IWineD3DSurfaceImpl_GetDevice,
3627 IWineD3DSurfaceImpl_SetPrivateData,
3628 IWineD3DSurfaceImpl_GetPrivateData,
3629 IWineD3DSurfaceImpl_FreePrivateData,
3630 IWineD3DSurfaceImpl_SetPriority,
3631 IWineD3DSurfaceImpl_GetPriority,
3632 IWineD3DSurfaceImpl_PreLoad,
3633 IWineD3DSurfaceImpl_GetType,
3634 /* IWineD3DSurface */
3635 IWineD3DSurfaceImpl_GetContainer,
3636 IWineD3DSurfaceImpl_GetDesc,
3637 IWineD3DSurfaceImpl_LockRect,
3638 IWineD3DSurfaceImpl_UnlockRect,
3639 IWineD3DSurfaceImpl_GetDC,
3640 IWineD3DSurfaceImpl_ReleaseDC,
3641 IWineD3DSurfaceImpl_Flip,
3642 IWineD3DSurfaceImpl_Blt,
3643 IWineD3DSurfaceImpl_GetBltStatus,
3644 IWineD3DSurfaceImpl_GetFlipStatus,
3645 IWineD3DSurfaceImpl_IsLost,
3646 IWineD3DSurfaceImpl_Restore,
3647 IWineD3DSurfaceImpl_BltFast,
3648 IWineD3DSurfaceImpl_GetPalette,
3649 IWineD3DSurfaceImpl_SetPalette,
3650 IWineD3DSurfaceImpl_RealizePalette,
3651 IWineD3DSurfaceImpl_SetColorKey,
3652 IWineD3DSurfaceImpl_GetPitch,
3653 IWineD3DSurfaceImpl_SetMem,
3654 IWineD3DSurfaceImpl_SetOverlayPosition,
3655 IWineD3DSurfaceImpl_GetOverlayPosition,
3656 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3657 IWineD3DSurfaceImpl_UpdateOverlay,
3658 IWineD3DSurfaceImpl_SetClipper,
3659 IWineD3DSurfaceImpl_GetClipper,
3661 IWineD3DSurfaceImpl_AddDirtyRect,
3662 IWineD3DSurfaceImpl_LoadTexture,
3663 IWineD3DSurfaceImpl_SaveSnapshot,
3664 IWineD3DSurfaceImpl_SetContainer,
3665 IWineD3DSurfaceImpl_SetGlTextureDesc,
3666 IWineD3DSurfaceImpl_GetGlDesc,
3667 IWineD3DSurfaceImpl_GetData,
3668 IWineD3DSurfaceImpl_SetFormat,
3669 IWineD3DSurfaceImpl_PrivateSetup