2 * IWineD3DSurface Implementation
4 * Copyright 1998 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 * Copyright 2002-2005 Jason Edmeades
7 * Copyright 2002-2003 Raphael Junqueira
8 * Copyright 2004 Christian Costa
9 * Copyright 2005 Oliver Stieber
10 * Copyright 2006 Stefan Dösinger for CodeWeavers
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "wine/port.h"
29 #include "wined3d_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
32 #define GLINFO_LOCATION ((IWineD3DImpl *)(((IWineD3DDeviceImpl *)This->resource.wineD3DDevice)->wineD3D))->gl_info
50 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf);
52 static void surface_download_data(IWineD3DSurfaceImpl *This) {
53 if (This->resource.format == WINED3DFMT_DXT1 ||
54 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
55 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
56 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) { /* We can assume this as the texture would not have been created otherwise */
57 FIXME("(%p) : Attempting to lock a compressed texture when texture compression isn't supported by opengl\n", This);
59 TRACE("(%p) : Calling glGetCompressedTexImageARB level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
60 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
64 GL_EXTCALL(glGetCompressedTexImageARB(This->glDescription.target, This->glDescription.level, This->resource.allocatedMemory));
65 checkGLcall("glGetCompressedTexImageARB()");
70 TRACE("(%p) : Calling glGetTexImage level %d, format %#x, type %#x, data %p\n", This, This->glDescription.level,
71 This->glDescription.glFormat, This->glDescription.glType, This->resource.allocatedMemory);
75 glGetTexImage(This->glDescription.target, This->glDescription.level, This->glDescription.glFormat,
76 This->glDescription.glType, This->resource.allocatedMemory);
77 checkGLcall("glGetTexImage()");
81 if (wined3d_settings.nonpower2_mode == NP2_REPACK) {
83 * Some games (e.g. warhammer 40k) don't work properly with the odd pitches, preventing
84 * the surface pitch from being used to box non-power2 textures. Instead we have to use a hack to
85 * repack the texture so that the bpp * width pitch can be used instead of bpp * pow2width.
89 * instead of boxing the texture :
90 * |<-texture width ->| -->pow2width| /\
91 * |111111111111111111| | |
92 * |222 Texture 222222| boxed empty | texture height
93 * |3333 Data 33333333| | |
94 * |444444444444444444| | \/
95 * ----------------------------------- |
96 * | boxed empty | boxed empty | pow2height
98 * -----------------------------------
101 * we're repacking the data to the expected texture width
103 * |<-texture width ->| -->pow2width| /\
104 * |111111111111111111222222222222222| |
105 * |222333333333333333333444444444444| texture height
109 * | empty | pow2height
111 * -----------------------------------
115 * |<-texture width ->| /\
116 * |111111111111111111|
117 * |222222222222222222|texture height
118 * |333333333333333333|
119 * |444444444444444444| \/
120 * --------------------
122 * this also means that any references to allocatedMemory should work with the data as if were a
123 * standard texture with a non-power2 width instead of texture boxed up to be a power2 texture.
125 * internally the texture is still stored in a boxed format so any references to textureName will
126 * get a boxed texture with width pow2width and not a texture of width currentDesc.Width.
129 if (This->Flags & SFLAG_NONPOW2) {
130 LPBYTE src_data, dst_data;
131 int src_pitch = This->bytesPerPixel * This->pow2Width;
132 int dst_pitch = This->bytesPerPixel * This->currentDesc.Width;
135 src_data = dst_data = This->resource.allocatedMemory;
136 FIXME("(%p) : Repacking the surface data from pitch %d to pitch %d\n", This, src_pitch, dst_pitch);
137 for (y = 1 ; y < This->currentDesc.Height; y++) {
138 /* skip the first row */
139 src_data += src_pitch;
140 dst_data += dst_pitch;
141 memcpy(dst_data, src_data, dst_pitch);
148 static void surface_upload_data(IWineD3DSurfaceImpl *This, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *data) {
149 if (This->resource.format == WINED3DFMT_DXT1 ||
150 This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
151 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) {
152 if (!GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
153 FIXME("Using DXT1/3/5 without advertized support\n");
155 TRACE("(%p) : Calling glCompressedTexSubImage2D w %d, h %d, data %p\n", This, width, height, data);
157 GL_EXTCALL(glCompressedTexSubImage2DARB(This->glDescription.target, This->glDescription.level, 0, 0, width, height,
158 This->glDescription.glFormatInternal, This->resource.size, data));
159 checkGLcall("glCompressedTexSubImage2D");
163 TRACE("(%p) : Calling glTexSubImage2D w %d, h %d, data, %p\n", This, width, height, data);
165 glTexSubImage2D(This->glDescription.target, This->glDescription.level, 0, 0, width, height, format, type, data);
166 checkGLcall("glTexSubImage2D");
171 static void surface_allocate_surface(IWineD3DSurfaceImpl *This, GLenum internal, GLsizei width, GLsizei height, GLenum format, GLenum type) {
172 TRACE("(%p) : Creating surface (target %#x) level %d, d3d format %s, internal format %#x, width %d, height %d, gl format %#x, gl type=%#x\n", This,
173 This->glDescription.target, This->glDescription.level, debug_d3dformat(This->resource.format), internal, width, height, format, type);
177 glTexImage2D(This->glDescription.target, This->glDescription.level, internal, width, height, 0, format, type, NULL);
178 checkGLcall("glTexImage2D");
183 /* *******************************************
184 IWineD3DSurface IUnknown parts follow
185 ******************************************* */
186 HRESULT WINAPI IWineD3DSurfaceImpl_QueryInterface(IWineD3DSurface *iface, REFIID riid, LPVOID *ppobj)
188 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
189 /* Warn ,but be nice about things */
190 TRACE("(%p)->(%s,%p)\n", This,debugstr_guid(riid),ppobj);
192 ERR("Probably FIXME: Calling query interface with NULL riid\n");
194 if (IsEqualGUID(riid, &IID_IUnknown)
195 || IsEqualGUID(riid, &IID_IWineD3DBase)
196 || IsEqualGUID(riid, &IID_IWineD3DResource)
197 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
198 IUnknown_AddRef((IUnknown*)iface);
203 return E_NOINTERFACE;
206 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
207 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
208 ULONG ref = InterlockedIncrement(&This->resource.ref);
209 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
213 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
214 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
215 ULONG ref = InterlockedDecrement(&This->resource.ref);
216 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
218 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
219 TRACE("(%p) : cleaning up\n", This);
220 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
222 TRACE("Deleting texture %d\n", This->glDescription.textureName);
223 glDeleteTextures(1, &This->glDescription.textureName);
227 if(This->Flags & SFLAG_DIBSECTION) {
229 SelectObject(This->hDC, This->dib.holdbitmap);
231 /* Release the DIB section */
232 DeleteObject(This->dib.DIBsection);
233 This->dib.bitmap_data = NULL;
234 This->resource.allocatedMemory = NULL;
236 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
238 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
239 if(iface == device->ddraw_primary)
240 device->ddraw_primary = NULL;
242 TRACE("(%p) Released\n", This);
243 HeapFree(GetProcessHeap(), 0, This);
249 /* ****************************************************
250 IWineD3DSurface IWineD3DResource parts follow
251 **************************************************** */
252 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
253 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
256 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
257 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
260 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
261 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
264 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
265 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
268 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
269 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
272 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
273 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
276 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
277 /* TODO: re-write the way textures and managed,
278 * use a 'opengl context manager' to manage RenderTarget surfaces
279 ** *********************************************************/
281 /* TODO: check for locks */
282 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
283 IWineD3DBaseTexture *baseTexture = NULL;
284 TRACE("(%p)Checking to see if the container is a base texture\n", This);
285 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
286 TRACE("Passing to conatiner\n");
287 IWineD3DBaseTexture_PreLoad(baseTexture);
288 IWineD3DBaseTexture_Release(baseTexture);
290 TRACE("(%p) : About to load surface\n", This);
292 #if 0 /* TODO: context manager support */
293 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
295 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
296 if (!This->glDescription.level) {
297 if (!This->glDescription.textureName) {
298 glGenTextures(1, &This->glDescription.textureName);
299 checkGLcall("glGenTextures");
300 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
302 glBindTexture(This->glDescription.target, This->glDescription.textureName);
303 checkGLcall("glBindTexture");
304 IWineD3DSurface_LoadTexture(iface);
305 /* This is where we should be reducing the amount of GLMemoryUsed */
306 } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
307 /* assume this is a coding error not a real error for now */
308 FIXME("Mipmap surface has a glTexture bound to it!\n");
310 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
311 /* Tell opengl to try and keep this texture in video ram (well mostly) */
314 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
316 /* TODO: disable texture support, if it wastn't enabled when we entered. */
317 #if 0 /* TODO: context manager support */
318 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
319 /* we don't care when the state is disabled(if atall) */);
326 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
327 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
328 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
331 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
332 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
333 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
336 /* ******************************************************
337 IWineD3DSurface IWineD3DSurface parts follow
338 ****************************************************** */
340 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
341 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
342 IWineD3DBase *container = 0;
344 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
347 ERR("Called without a valid ppContainer.\n");
351 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
352 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
353 * GetContainer will return the Direct3D device used to create the surface.
355 if (This->container) {
356 container = This->container;
358 container = (IWineD3DBase *)This->resource.wineD3DDevice;
361 TRACE("Relaying to QueryInterface\n");
362 return IUnknown_QueryInterface(container, riid, ppContainer);
365 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
366 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
368 TRACE("(%p) : copying into %p\n", This, pDesc);
369 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
370 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
371 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
372 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
373 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
374 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
375 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
376 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
377 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
381 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
382 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
383 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
384 if (This->glDescription.textureName == 0 && textureName != 0) {
385 This->Flags |= SFLAG_DIRTY;
386 IWineD3DSurface_AddDirtyRect(iface, NULL);
388 This->glDescription.textureName = textureName;
389 This->glDescription.target = target;
392 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
393 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
394 TRACE("(%p) : returning %p\n", This, &This->glDescription);
395 *glDescription = &This->glDescription;
398 /* TODO: think about moving this down to resource? */
399 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
400 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
401 /* This should only be called for sysmem textures, it may be a good idea to extend this to all pools at some point in the futture */
402 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
403 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
405 return (CONST void*)(This->resource.allocatedMemory);
408 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
414 switch(This->resource.format)
418 /* GL can't return palettized data, so read ARGB pixels into a
419 * separate block of memory and convert them into palettized format
420 * in software. Slow, but if the app means to use palettized render
421 * targets and locks it...
423 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
424 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
425 * for the color channels when palettizing the colors.
428 type = GL_UNSIGNED_BYTE;
430 mem = HeapAlloc(GetProcessHeap(), 0, (rect->bottom - rect->top) * pitch);
432 ERR("Out of memory\n");
440 fmt = This->glDescription.glFormat;
441 type = This->glDescription.glType;
444 if (rect->left == 0 &&
445 rect->right == This->currentDesc.Width ) {
446 BYTE *row, *top, *bottom;
449 glReadPixels(0, rect->top,
450 This->currentDesc.Width,
451 rect->bottom - rect->top,
456 /* glReadPixels returns the image upside down, and there is no way to prevent this.
457 Flip the lines in software */
458 row = HeapAlloc(GetProcessHeap(), 0, pitch);
460 ERR("Out of memory\n");
464 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
465 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
466 memcpy(row, top, pitch);
467 memcpy(top, bottom, pitch);
468 memcpy(bottom, row, pitch);
472 HeapFree(GetProcessHeap(), 0, row);
474 if(This->lockedRect.top == 0 && This->lockedRect.bottom == This->currentDesc.Height) {
475 This->Flags &= ~SFLAG_GLDIRTY;
478 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
479 glReadPixels(rect->left,
480 rect->bottom - j - 1,
481 rect->right - rect->left,
485 (char *)mem + (pitch * (j-rect->top)));
489 vcheckGLcall("glReadPixels");
491 if(This->resource.format == WINED3DFMT_P8) {
493 DWORD width = pitch / 3;
496 pal = This->palette->palents;
498 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
501 for(y = rect->top; y < rect->bottom; y++) {
502 for(x = rect->left; x < rect->right; x++) {
503 /* start lines pixels */
504 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
505 BYTE *green = blue + 1;
506 BYTE *red = green + 1;
508 for(c = 0; c < 256; c++) {
509 if(*red == pal[c].peRed &&
510 *green == pal[c].peGreen &&
511 *blue == pal[c].peBlue)
513 *((BYTE *) dest + y * width + x) = c;
519 HeapFree(GetProcessHeap(), 0, mem);
523 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
524 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
525 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
526 IWineD3DSwapChainImpl *swapchain = NULL;
527 static UINT messages = 0; /* holds flags to disable fixme messages */
528 BOOL backbuf = FALSE;
530 /* fixme: should we really lock as such? */
531 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
532 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
533 FIXME("Warning: Surface is in texture memory or pbuffer\n");
534 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
537 if (!(This->Flags & SFLAG_LOCKABLE)) {
538 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
539 texture regions, and since the destination is an unlockable region we need
541 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
542 /*return WINED3DERR_INVALIDCALL; */
545 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
546 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
548 if (swapchain != NULL || iface == myDevice->render_targets[0] || iface == myDevice->depthStencilBuffer) {
549 if(swapchain != NULL) {
551 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
552 if(iface == swapchain->backBuffer[i]) {
559 TRACE("(%p, backBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
560 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
561 TRACE("(%p, frontBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
562 } else if (iface == myDevice->render_targets[0]) {
563 TRACE("(%p, renderTarget) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
564 } else if (iface == myDevice->depthStencilBuffer) {
565 TRACE("(%p, stencilBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
568 if (NULL != swapchain) {
569 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
574 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
577 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
580 pLockedRect->pBits = This->resource.allocatedMemory;
581 This->lockedRect.left = 0;
582 This->lockedRect.top = 0;
583 This->lockedRect.right = This->currentDesc.Width;
584 This->lockedRect.bottom = This->currentDesc.Height;
585 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
587 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
589 if ((pRect->top < 0) ||
591 (pRect->left >= pRect->right) ||
592 (pRect->top >= pRect->bottom) ||
593 (pRect->right > This->currentDesc.Width) ||
594 (pRect->bottom > This->currentDesc.Height))
596 WARN(" Invalid values in pRect !!!\n");
597 return D3DERR_INVALIDCALL;
600 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
601 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
603 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
605 This->lockedRect.left = pRect->left;
606 This->lockedRect.top = pRect->top;
607 This->lockedRect.right = pRect->right;
608 This->lockedRect.bottom = pRect->bottom;
611 if (This->Flags & SFLAG_NONPOW2) {
612 TRACE("Locking non-power 2 texture\n");
615 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
616 /* classic surface TODO: non 2d surfaces?
617 These resources may be POOL_SYSTEMMEM, so they must not access the device */
618 TRACE("locking an ordinarary surface\n");
619 /* Check to see if memory has already been allocated from the surface*/
620 if ((NULL == This->resource.allocatedMemory) ||
621 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
622 /* Non-system memory surfaces */
624 This->Flags &= ~SFLAG_GLDIRTY;
626 /*Surface has no memory currently allocated to it!*/
627 TRACE("(%p) Locking rect\n" , This);
628 if(!This->resource.allocatedMemory) {
629 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
631 if (0 != This->glDescription.textureName) {
632 /* Now I have to copy thing bits back */
633 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
634 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
636 /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
637 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
639 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
640 checkGLcall("glActiveTextureARB");
643 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
644 IWineD3DSurface_PreLoad(iface);
646 surface_download_data(This);
648 } else { /* Nothing to do */
649 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
653 pLockedRect->pBits = This->resource.allocatedMemory;
655 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
656 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
658 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
662 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
663 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
666 BOOL notInContext = FALSE;
667 IWineD3DSwapChainImpl *targetSwapChain = NULL;
673 * for render->surface copy begin to begin of allocatedMemory
674 * unlock can be more easy
677 TRACE("locking a render target\n");
679 if (This->resource.allocatedMemory == NULL)
680 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
682 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
683 pLockedRect->pBits = This->resource.allocatedMemory;
686 vcheckGLcall("glFlush");
687 glGetIntegerv(GL_READ_BUFFER, &prev_read);
688 vcheckGLcall("glIntegerv");
689 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
690 vcheckGLcall("glIntegerv");
692 /* Here's what we have to do:
693 See if the swapchain has the same context as the renderTarget or the surface is the render target.
694 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
695 and use the front back buffer as required.
696 if not, we need to switch contexts and then switchback at the end.
698 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
699 IWineD3DSurface_GetContainer(myDevice->render_targets[0], &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
701 /* NOTE: In a shared context environment the renderTarget will use the same context as the implicit swapchain (we're not in a shared environment yet! */
702 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->render_targets[0]) {
703 if (swapchain && iface == swapchain->frontBuffer) {
704 TRACE("locking front\n");
705 glReadBuffer(GL_FRONT);
707 else if (iface == myDevice->render_targets[0] || backbuf) {
708 TRACE("locking back buffer\n");
709 glReadBuffer(GL_BACK);
710 } else if (iface == myDevice->depthStencilBuffer) {
711 FIXME("Stencil Buffer lock unsupported for now\n");
713 FIXME("(%p) Shouldn't have got here!\n", This);
714 glReadBuffer(GL_BACK);
716 } else if (swapchain != NULL) {
717 IWineD3DSwapChainImpl *implSwapChain;
718 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
719 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
720 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
722 glReadBuffer(GL_BACK);
723 } else if (iface == swapchain->frontBuffer) {
724 glReadBuffer(GL_FRONT);
725 } else if (iface == myDevice->depthStencilBuffer) {
726 FIXME("Stencil Buffer lock unsupported for now\n");
728 FIXME("Should have got here!\n");
729 glReadBuffer(GL_BACK);
732 /* We need to switch contexts to be able to read the buffer!!! */
733 FIXME("The buffer requested isn't in the current openGL context\n");
735 /* TODO: check the contexts, to see if were shared with the current context */
737 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
739 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
740 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
742 /** the depth stencil in openGL has a format of GL_FLOAT
743 * which should be good for WINED3DFMT_D16_LOCKABLE
745 * it is unclear what format the stencil buffer is in except.
746 * 'Each index is converted to fixed point...
747 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
748 * mappings in the table GL_PIXEL_MAP_S_TO_S.
749 * glReadPixels(This->lockedRect.left,
750 * This->lockedRect.bottom - j - 1,
751 * This->lockedRect.right - This->lockedRect.left,
753 * GL_DEPTH_COMPONENT,
755 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
756 *****************************************/
757 if (!notInContext) { /* Only read the buffer if it's in the current context */
758 switch(wined3d_settings.rendertargetlock_mode) {
762 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
767 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
768 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
773 static BOOL warned = FALSE;
775 ERR("Application tries to lock the render target, but render target locking is disabled\n");
782 TRACE("Resetting buffer\n");
784 glReadBuffer(prev_read);
785 vcheckGLcall("glReadBuffer");
789 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
792 FIXME("TODO stencil depth surface locking surf%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
795 glReadPixels(This->lockedRect.left,
796 This->lockedRect.bottom - j - 1,
797 This->lockedRect.right - This->lockedRect.left,
799 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
806 FIXME("unsupported locking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
809 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
812 IWineD3DBaseTexture *pBaseTexture;
815 * as seen in msdn docs
817 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
819 /** Dirtify Container if needed */
820 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
821 TRACE("Making container dirty\n");
822 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
823 IWineD3DBaseTexture_Release(pBaseTexture);
825 TRACE("Surface is standalone, no need to dirty the container\n");
829 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
831 This->Flags |= SFLAG_LOCKED;
835 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
837 GLint prev_rasterpos[4];
839 BOOL storechanged = FALSE;
843 glDisable(GL_TEXTURE_2D);
844 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
845 glDisable(GL_TEXTURE_1D);
846 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
849 vcheckGLcall("glFlush");
850 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
851 vcheckGLcall("glIntegerv");
852 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
853 vcheckGLcall("glIntegerv");
854 glPixelZoom(1.0, -1.0);
855 vcheckGLcall("glPixelZoom");
857 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
858 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
859 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
861 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
862 vcheckGLcall("glRasterPos2f");
864 /* Some drivers(radeon dri, others?) don't like exceptions during
865 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
866 * after ReleaseDC. Reading it will cause an exception, which x11drv will
867 * catch to put the dib section in InSync mode, which leads to a crash
868 * and a blocked x server on my radeon card.
870 * The following lines read the dib section so it is put in inSync mode
871 * before glDrawPixels is called and the crash is prevented. There won't
872 * be any interfering gdi accesses, because UnlockRect is called from
873 * ReleaseDC, and the app won't use the dc any more afterwards.
875 if(This->Flags & SFLAG_DIBSECTION) {
877 read = This->resource.allocatedMemory[0];
880 switch (This->resource.format) {
881 /* No special care needed */
882 case WINED3DFMT_A4R4G4B4:
883 case WINED3DFMT_R5G6B5:
884 case WINED3DFMT_A1R5G5B5:
885 case WINED3DFMT_R8G8B8:
886 type = This->glDescription.glType;
887 fmt = This->glDescription.glFormat;
888 mem = This->resource.allocatedMemory;
891 case WINED3DFMT_X4R4G4B4:
894 unsigned short *data;
895 data = (unsigned short *)This->resource.allocatedMemory;
896 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
902 type = This->glDescription.glType;
903 fmt = This->glDescription.glFormat;
904 mem = This->resource.allocatedMemory;
908 case WINED3DFMT_X1R5G5B5:
911 unsigned short *data;
912 data = (unsigned short *)This->resource.allocatedMemory;
913 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
919 type = This->glDescription.glType;
920 fmt = This->glDescription.glFormat;
921 mem = This->resource.allocatedMemory;
925 case WINED3DFMT_X8R8G8B8:
927 /* make sure the X byte is set to alpha on, since it
928 could be any random value. This fixes the intro movie in Pirates! */
931 data = (unsigned int *)This->resource.allocatedMemory;
932 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
941 case WINED3DFMT_A8R8G8B8:
943 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
944 vcheckGLcall("glPixelStorei");
946 type = This->glDescription.glType;
947 fmt = This->glDescription.glFormat;
948 mem = This->resource.allocatedMemory;
952 case WINED3DFMT_A2R10G10B10:
954 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
955 vcheckGLcall("glPixelStorei");
957 type = This->glDescription.glType;
958 fmt = This->glDescription.glFormat;
959 mem = This->resource.allocatedMemory;
965 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
966 int height = This->glRect.bottom - This->glRect.top;
967 type = GL_UNSIGNED_BYTE;
970 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
972 ERR("Out of memory\n");
975 d3dfmt_convert_surface(This->resource.allocatedMemory,
987 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
990 type = This->glDescription.glType;
991 fmt = This->glDescription.glFormat;
992 mem = This->resource.allocatedMemory;
995 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
996 (This->lockedRect.bottom - This->lockedRect.top)-1,
999 checkGLcall("glDrawPixels");
1000 glPixelZoom(1.0,1.0);
1001 vcheckGLcall("glPixelZoom");
1003 glRasterPos3iv(&prev_rasterpos[0]);
1004 vcheckGLcall("glRasterPos3iv");
1006 /* Reset to previous pack row length */
1007 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1008 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1010 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
1011 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1014 if(mem != This->resource.allocatedMemory) HeapFree(GetProcessHeap(), 0, mem);
1018 static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
1019 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1020 float glTexCoord[4];
1022 glTexCoord[0] = 0.0; /* left */
1023 glTexCoord[1] = (float) This->currentDesc.Width / (float) This->pow2Width; /* right */
1024 glTexCoord[2] = 0.0; /* top */
1025 glTexCoord[3] = (float) This->currentDesc.Height / (float) This->pow2Height; /* bottom */
1027 IWineD3DSurface_PreLoad(iface);
1031 /* Disable some fancy graphics effects */
1032 glDisable(GL_LIGHTING);
1033 checkGLcall("glDisable GL_LIGHTING");
1034 glDisable(GL_DEPTH_TEST);
1035 checkGLcall("glDisable GL_DEPTH_TEST");
1037 checkGLcall("glDisable GL_FOG");
1038 glDisable(GL_CULL_FACE);
1039 checkGLcall("glDisable GL_CULL_FACE");
1040 glDisable(GL_BLEND);
1041 checkGLcall("glDisable GL_BLEND");
1042 glDisable(GL_STENCIL_TEST);
1043 checkGLcall("glDisable GL_STENCIL_TEST");
1045 glEnable(GL_TEXTURE_2D);
1046 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1047 checkGLcall("glEnable glBindTexture");
1049 /* No filtering for blts */
1050 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1051 checkGLcall("glTexParameteri");
1052 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1053 checkGLcall("glTexParameteri");
1055 /* Start drawing a quad */
1058 glColor3d(1.0f, 1.0f, 1.0f);
1059 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1060 glVertex3f(0, 0, 0.0);
1062 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1063 glVertex3f(0, This->currentDesc.Height, 0.0);
1065 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1066 glVertex3d(This->currentDesc.Width, This->currentDesc.Height, 0.0);
1068 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1069 glVertex3f(This->currentDesc.Width, 0, 0.0);
1072 checkGLcall("glEnd");
1074 /* Unbind the texture */
1075 glBindTexture(GL_TEXTURE_2D, 0);
1076 checkGLcall("glEnable glBindTexture");
1081 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1082 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1083 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1084 const char *buffername = "";
1085 IWineD3DSwapChainImpl *swapchain = NULL;
1086 BOOL backbuf = FALSE;
1088 if (!(This->Flags & SFLAG_LOCKED)) {
1089 WARN("trying to Unlock an unlocked surf@%p\n", This);
1090 return WINED3DERR_INVALIDCALL;
1093 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
1094 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1098 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
1099 if(iface == swapchain->backBuffer[i]) {
1107 buffername = "backBuffer";
1108 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
1109 buffername = "frontBuffer";
1110 } else if (iface == myDevice->depthStencilBuffer) {
1111 buffername = "depthStencilBuffer";
1112 } else if (iface == myDevice->render_targets[0]) {
1113 buffername = "renderTarget";
1117 if (swapchain != NULL) {
1118 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1121 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
1123 if (!(This->Flags & SFLAG_DIRTY)) {
1124 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1128 if (0 == This->resource.usage) { /* classic surface */
1129 IWineD3DBaseTextureImpl *impl;
1130 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1131 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1132 * states need resetting
1134 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1135 if(impl->baseTexture.bindCount) {
1136 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1138 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1140 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
1142 /****************************
1143 * TODO: Render targets are 'special' and
1144 * ?some? locking needs to be passed onto the context manager
1145 * so that it becomes possible to use auxiliary buffers, pbuffers
1146 * render-to-texture, shared, cached contexts etc...
1147 * ****************************/
1148 IWineD3DSwapChainImpl *implSwapChain;
1149 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
1151 if ((backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->render_targets[0]) && wined3d_settings.rendertargetlock_mode != RTL_DISABLE) {
1156 /* glDrawPixels transforms the raster position as though it was a vertex -
1157 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1158 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1159 myDevice->last_was_rhw = TRUE;
1160 /* Apply the projection and world matrices, it sets up orthogonal projection due to last_was_rhw */
1161 StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock);
1162 StateTable[STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))].apply(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), myDevice->stateBlock);
1163 /* Will reapply the projection matrix too */
1164 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL);
1166 if (iface == implSwapChain->frontBuffer) {
1167 glDrawBuffer(GL_FRONT);
1168 checkGLcall("glDrawBuffer GL_FRONT");
1169 } else if (backbuf || iface == myDevice->render_targets[0]) {
1170 glDrawBuffer(GL_BACK);
1171 checkGLcall("glDrawBuffer GL_BACK");
1174 /* Disable higher textures before calling glDrawPixels */
1175 for(tex = 1; tex < GL_LIMITS(samplers); tex++) {
1176 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1177 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + tex));
1178 checkGLcall("glActiveTextureARB");
1180 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(tex));
1181 glDisable(GL_TEXTURE_2D);
1182 checkGLcall("glDisable GL_TEXTURE_2D");
1183 glDisable(GL_TEXTURE_1D);
1184 checkGLcall("glDisable GL_TEXTURE_1D");
1186 /* Activate texture 0, but don't disable it necessarily */
1187 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1188 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1189 checkGLcall("glActiveTextureARB");
1191 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
1193 /* And back buffers are not blended. Disable the depth test,
1194 that helps performance */
1195 glDisable(GL_BLEND);
1196 glDisable(GL_DEPTH_TEST);
1199 switch(wined3d_settings.rendertargetlock_mode) {
1203 flush_to_framebuffer_drawpixels(This);
1208 flush_to_framebuffer_texture(iface);
1213 static BOOL warned = FALSE;
1215 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1222 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1223 glDrawBuffer(GL_BACK);
1224 vcheckGLcall("glDrawBuffer");
1226 if(myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_TRUE ||
1227 myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_USEW) glEnable(GL_DEPTH_TEST);
1228 if (myDevice->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1229 if (myDevice->stateBlock->renderState[WINED3DRS_FOGENABLE]) glEnable(GL_FOG);
1233 /** restore clean dirty state */
1234 IWineD3DSurface_CleanDirtyRect(iface);
1236 } else if(wined3d_settings.rendertargetlock_mode != RTL_DISABLE) {
1237 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1239 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1241 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1243 if (iface == myDevice->depthStencilBuffer) {
1244 FIXME("TODO stencil depth surface unlocking surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1246 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1250 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1254 This->Flags &= ~SFLAG_LOCKED;
1255 memset(&This->lockedRect, 0, sizeof(RECT));
1259 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1260 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1261 WINED3DLOCKED_RECT lock;
1268 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1270 TRACE("(%p)->(%p)\n",This,pHDC);
1272 if(This->Flags & SFLAG_USERPTR) {
1273 ERR("Not supported on surfaces with an application-provided surfaces\n");
1277 /* Give more detailed info for ddraw */
1278 if (This->Flags & SFLAG_DCINUSE)
1279 return DDERR_DCALREADYCREATED;
1281 /* Can't GetDC if the surface is locked */
1282 if (This->Flags & SFLAG_LOCKED)
1283 return WINED3DERR_INVALIDCALL;
1285 memset(&lock, 0, sizeof(lock)); /* To be sure */
1287 /* Create a DIB section if there isn't a hdc yet */
1290 SYSTEM_INFO sysInfo;
1292 if(This->Flags & SFLAG_ACTIVELOCK) {
1293 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1296 switch (This->bytesPerPixel) {
1299 /* Allocate extra space to store the RGB bit masks. */
1300 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1304 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1308 /* Allocate extra space for a palette. */
1309 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1310 sizeof(BITMAPINFOHEADER)
1312 * (1 << (This->bytesPerPixel * 8)));
1317 return E_OUTOFMEMORY;
1319 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1320 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1321 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1322 * add an extra line to the dib section
1324 GetSystemInfo(&sysInfo);
1325 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1327 TRACE("Adding an extra line to the dib section\n");
1330 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1331 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1332 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1333 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1334 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1335 /* Use the full pow2 image size(assigned below) because LockRect
1336 * will need it for a full glGetTexImage call
1339 b_info->bmiHeader.biWidth = This->pow2Width;
1340 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1341 b_info->bmiHeader.biSizeImage = This->resource.size + extraline * IWineD3DSurface_GetPitch(iface);
1343 b_info->bmiHeader.biPlanes = 1;
1344 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1346 b_info->bmiHeader.biXPelsPerMeter = 0;
1347 b_info->bmiHeader.biYPelsPerMeter = 0;
1348 b_info->bmiHeader.biClrUsed = 0;
1349 b_info->bmiHeader.biClrImportant = 0;
1351 /* Get the bit masks */
1352 masks = (DWORD *) &(b_info->bmiColors);
1353 switch (This->resource.format) {
1354 case WINED3DFMT_R8G8B8:
1355 usage = DIB_RGB_COLORS;
1356 b_info->bmiHeader.biCompression = BI_RGB;
1359 case WINED3DFMT_X1R5G5B5:
1360 case WINED3DFMT_A1R5G5B5:
1361 case WINED3DFMT_A4R4G4B4:
1362 case WINED3DFMT_X4R4G4B4:
1363 case WINED3DFMT_R3G3B2:
1364 case WINED3DFMT_A8R3G3B2:
1365 case WINED3DFMT_A2B10G10R10:
1366 case WINED3DFMT_A8B8G8R8:
1367 case WINED3DFMT_X8B8G8R8:
1368 case WINED3DFMT_A2R10G10B10:
1369 case WINED3DFMT_R5G6B5:
1370 case WINED3DFMT_A16B16G16R16:
1372 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1373 masks[0] = formatEntry->redMask;
1374 masks[1] = formatEntry->greenMask;
1375 masks[2] = formatEntry->blueMask;
1379 /* Don't know palette */
1380 b_info->bmiHeader.biCompression = BI_RGB;
1387 HeapFree(GetProcessHeap(), 0, b_info);
1388 return HRESULT_FROM_WIN32(GetLastError());
1391 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);
1392 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1395 if (!This->dib.DIBsection) {
1396 ERR("CreateDIBSection failed!\n");
1397 HeapFree(GetProcessHeap(), 0, b_info);
1398 return HRESULT_FROM_WIN32(GetLastError());
1401 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1403 /* copy the existing surface to the dib section */
1404 if(This->resource.allocatedMemory) {
1405 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1406 /* We won't need that any more */
1407 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1409 /* This is to make LockRect read the gl Texture although memory is allocated */
1410 This->Flags |= SFLAG_GLDIRTY;
1413 HeapFree(GetProcessHeap(), 0, b_info);
1415 /* Use the dib section from now on */
1416 This->resource.allocatedMemory = This->dib.bitmap_data;
1418 /* Now allocate a HDC */
1419 This->hDC = CreateCompatibleDC(0);
1420 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1421 TRACE("using wined3d palette %p\n", This->palette);
1422 SelectPalette(This->hDC,
1423 This->palette ? This->palette->hpal : 0,
1426 This->Flags |= SFLAG_DIBSECTION;
1429 /* Lock the surface */
1430 hr = IWineD3DSurface_LockRect(iface,
1435 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1436 /* keep the dib section */
1440 if(This->resource.format == WINED3DFMT_P8 ||
1441 This->resource.format == WINED3DFMT_A8P8) {
1444 PALETTEENTRY ent[256];
1446 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1447 for (n=0; n<256; n++) {
1448 col[n].rgbRed = ent[n].peRed;
1449 col[n].rgbGreen = ent[n].peGreen;
1450 col[n].rgbBlue = ent[n].peBlue;
1451 col[n].rgbReserved = 0;
1454 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1456 for (n=0; n<256; n++) {
1457 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1458 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1459 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1460 col[n].rgbReserved = 0;
1464 SetDIBColorTable(This->hDC, 0, 256, col);
1468 TRACE("returning %p\n",*pHDC);
1469 This->Flags |= SFLAG_DCINUSE;
1474 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1475 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1477 TRACE("(%p)->(%p)\n",This,hDC);
1479 if (!(This->Flags & SFLAG_DCINUSE))
1480 return D3DERR_INVALIDCALL;
1482 /* we locked first, so unlock now */
1483 IWineD3DSurface_UnlockRect(iface);
1485 This->Flags &= ~SFLAG_DCINUSE;
1490 /* ******************************************************
1491 IWineD3DSurface Internal (No mapping to directx api) parts follow
1492 ****************************************************** */
1494 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) {
1495 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1496 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1498 /* Default values: From the surface */
1499 *format = formatEntry->glFormat;
1500 *internal = formatEntry->glInternal;
1501 *type = formatEntry->glType;
1502 *convert = NO_CONVERSION;
1503 *target_bpp = This->bytesPerPixel;
1505 /* Ok, now look if we have to do any conversion */
1506 switch(This->resource.format) {
1511 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1512 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1514 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1516 *internal = GL_RGBA;
1517 *type = GL_UNSIGNED_BYTE;
1519 if(colorkey_active) {
1520 *convert = CONVERT_PALETTED_CK;
1522 *convert = CONVERT_PALETTED;
1528 case WINED3DFMT_R3G3B2:
1529 /* **********************
1530 GL_UNSIGNED_BYTE_3_3_2
1531 ********************** */
1532 if (colorkey_active) {
1533 /* This texture format will never be used.. So do not care about color keying
1534 up until the point in time it will be needed :-) */
1535 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1539 case WINED3DFMT_R5G6B5:
1540 if (colorkey_active) {
1541 *convert = CONVERT_CK_565;
1543 *internal = GL_RGBA;
1544 *type = GL_UNSIGNED_SHORT_5_5_5_1;
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;
1574 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1575 BYTE *source, *dest;
1576 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1581 memcpy(dst, src, pitch * height);
1584 case CONVERT_PALETTED:
1585 case CONVERT_PALETTED_CK:
1587 IWineD3DPaletteImpl* pal = surf->palette;
1593 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1597 /* Still no palette? Use the device's palette */
1598 /* Get the surface's palette */
1599 for (i = 0; i < 256; i++) {
1600 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1602 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1603 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1604 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1605 if ((convert == CONVERT_PALETTED_CK) &&
1606 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1607 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1608 /* We should maybe here put a more 'neutral' color than the standard bright purple
1609 one often used by application to prevent the nice purple borders when bi-linear
1617 TRACE("Using surface palette %p\n", pal);
1618 /* Get the surface's palette */
1619 for (i = 0; i < 256; i++) {
1620 table[i][0] = pal->palents[i].peRed;
1621 table[i][1] = pal->palents[i].peGreen;
1622 table[i][2] = pal->palents[i].peBlue;
1623 if ((convert == CONVERT_PALETTED_CK) &&
1624 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1625 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1626 /* We should maybe here put a more 'neutral' color than the standard bright purple
1627 one often used by application to prevent the nice purple borders when bi-linear
1636 for (y = 0; y < height; y++)
1638 source = src + pitch * y;
1639 dest = dst + outpitch * y;
1640 /* This is an 1 bpp format, using the width here is fine */
1641 for (x = 0; x < width; x++) {
1642 BYTE color = *source++;
1643 *dest++ = table[color][0];
1644 *dest++ = table[color][1];
1645 *dest++ = table[color][2];
1646 *dest++ = table[color][3];
1652 case CONVERT_CK_565:
1654 /* Converting the 565 format in 5551 packed to emulate color-keying.
1656 Note : in all these conversion, it would be best to average the averaging
1657 pixels to get the color of the pixel that will be color-keyed to
1658 prevent 'color bleeding'. This will be done later on if ever it is
1661 Note2: Nvidia documents say that their driver does not support alpha + color keying
1662 on the same surface and disables color keying in such a case
1668 TRACE("Color keyed 565\n");
1670 for (y = 0; y < height; y++) {
1671 Source = (WORD *) (src + y * pitch);
1672 Dest = (WORD *) (dst + y * outpitch);
1673 for (x = 0; x < width; x++ ) {
1674 WORD color = *Source++;
1675 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1676 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1677 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1687 ERR("Unsupported conversation type %d\n", convert);
1692 /* This function is used in case of 8bit paletted textures to upload the palette.
1693 For now it only supports GL_EXT_paletted_texture extension but support for other
1694 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1696 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1697 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1698 IWineD3DPaletteImpl* pal = This->palette;
1703 /* Still no palette? Use the device's palette */
1704 /* Get the surface's palette */
1705 for (i = 0; i < 256; i++) {
1706 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1708 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1709 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1710 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1711 if ((convert == CONVERT_PALETTED_CK) &&
1712 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1713 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1714 /* We should maybe here put a more 'neutral' color than the standard bright purple
1715 one often used by application to prevent the nice purple borders when bi-linear
1723 TRACE("Using surface palette %p\n", pal);
1724 /* Get the surface's palette */
1725 for (i = 0; i < 256; i++) {
1726 table[i][0] = pal->palents[i].peRed;
1727 table[i][1] = pal->palents[i].peGreen;
1728 table[i][2] = pal->palents[i].peBlue;
1729 if ((convert == CONVERT_PALETTED_CK) &&
1730 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1731 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1732 /* We should maybe here put a more 'neutral' color than the standard bright purple
1733 one often used by application to prevent the nice purple borders when bi-linear
1741 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1744 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1745 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1746 GLenum format, internal, type;
1747 CONVERT_TYPES convert;
1749 int width, pitch, outpitch;
1752 if (This->Flags & SFLAG_INTEXTURE) {
1753 TRACE("Surface already in texture\n");
1756 if (This->Flags & SFLAG_DIRTY) {
1757 TRACE("Reloading because surface is dirty\n");
1758 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1759 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1760 /* Reload: vice versa OR */
1761 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1762 /* Also reload: Color key is active AND the color key has changed */
1763 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1764 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1765 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1766 TRACE("Reloading because of color keying\n");
1768 TRACE("surface isn't dirty\n");
1772 This->Flags &= ~SFLAG_DIRTY;
1774 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1775 * These resources are not bound by device size or format restrictions. Because of this,
1776 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1777 * However, these resources can always be created, locked, and copied.
1779 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1781 FIXME("(%p) Operation not supported for scratch textures\n",This);
1782 return WINED3DERR_INVALIDCALL;
1785 if (This->Flags & SFLAG_INPBUFFER) {
1786 if (This->glDescription.level != 0)
1787 FIXME("Surface in texture is only supported for level 0\n");
1788 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1789 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1790 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1791 This->resource.format == WINED3DFMT_DXT5)
1792 FIXME("Format %d not supported\n", This->resource.format);
1798 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1799 vcheckGLcall("glGetIntegerv");
1800 glReadBuffer(GL_BACK);
1801 vcheckGLcall("glReadBuffer");
1803 glCopyTexImage2D(This->glDescription.target,
1804 This->glDescription.level,
1805 This->glDescription.glFormatInternal,
1808 This->currentDesc.Width,
1809 This->currentDesc.Height,
1812 checkGLcall("glCopyTexImage2D");
1813 glReadBuffer(prevRead);
1814 vcheckGLcall("glReadBuffer");
1818 TRACE("Updating target %d\n", This->glDescription.target);
1819 This->Flags |= SFLAG_INTEXTURE;
1824 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1825 This->Flags |= SFLAG_GLCKEY;
1826 This->glCKey = This->SrcBltCKey;
1828 else This->Flags &= ~SFLAG_GLCKEY;
1830 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1832 /* The width is in 'length' not in bytes */
1833 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1834 width = This->currentDesc.Width;
1836 width = This->pow2Width;
1838 pitch = IWineD3DSurface_GetPitch(iface);
1840 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1841 int height = This->glRect.bottom - This->glRect.top;
1843 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1844 outpitch = width * bpp;
1845 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1847 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1849 ERR("Out of memory %d, %d!\n", outpitch, height);
1850 return WINED3DERR_OUTOFVIDEOMEMORY;
1852 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1854 This->Flags |= SFLAG_CONVERTED;
1855 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1856 d3dfmt_p8_upload_palette(iface, convert);
1857 This->Flags &= ~SFLAG_CONVERTED;
1858 mem = This->resource.allocatedMemory;
1860 This->Flags &= ~SFLAG_CONVERTED;
1861 mem = This->resource.allocatedMemory;
1864 /* Make sure the correct pitch is used */
1865 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1867 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1868 TRACE("non power of two support\n");
1869 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1871 surface_upload_data(This, This->pow2Width, This->pow2Height, format, type, mem);
1874 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1876 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1880 /* Restore the default pitch */
1881 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1883 if (mem != This->resource.allocatedMemory)
1884 HeapFree(GetProcessHeap(), 0, mem);
1888 static unsigned int gen = 0;
1891 if ((gen % 10) == 0) {
1892 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1893 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1896 * debugging crash code
1905 if (!(This->Flags & SFLAG_DONOTFREE)) {
1906 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1907 This->resource.allocatedMemory = NULL;
1915 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1918 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1919 char *allocatedMemory;
1921 IWineD3DSwapChain *swapChain = NULL;
1923 GLuint tmpTexture = 0;
1926 Textures my not be stored in ->allocatedgMemory and a GlTexture
1927 so we should lock the surface before saving a snapshot, or at least check that
1929 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1930 by calling GetTexImage and in compressed form by calling
1931 GetCompressedTexImageARB. Queried compressed images can be saved and
1932 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1933 texture images do not need to be processed by the GL and should
1934 significantly improve texture loading performance relative to uncompressed
1937 /* Setup the width and height to be the internal texture width and height. */
1938 width = This->pow2Width;
1939 height = This->pow2Height;
1940 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1941 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1943 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1944 /* we don't want to interfere with the back buffer so read the data into a temporary texture and then save the data out of the temporary texture */
1947 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1948 glEnable(GL_TEXTURE_2D);
1950 glGenTextures(1, &tmpTexture);
1951 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1953 glTexImage2D(GL_TEXTURE_2D,
1960 GL_UNSIGNED_INT_8_8_8_8_REV,
1963 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1964 vcheckGLcall("glGetIntegerv");
1965 glReadBuffer(GL_BACK);
1966 vcheckGLcall("glReadBuffer");
1967 glCopyTexImage2D(GL_TEXTURE_2D,
1976 checkGLcall("glCopyTexImage2D");
1977 glReadBuffer(prevRead);
1980 } else { /* bind the real texture */
1981 IWineD3DSurface_PreLoad(iface);
1983 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1985 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1986 glGetTexImage(GL_TEXTURE_2D,
1987 This->glDescription.level,
1989 GL_UNSIGNED_INT_8_8_8_8_REV,
1991 checkGLcall("glTexImage2D");
1993 glBindTexture(GL_TEXTURE_2D, 0);
1994 glDeleteTextures(1, &tmpTexture);
1998 f = fopen(filename, "w+");
2000 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2001 return WINED3DERR_INVALIDCALL;
2003 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
2004 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2019 fwrite(&width,2,1,f);
2021 fwrite(&height,2,1,f);
2026 /* 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*/
2028 textureRow = allocatedMemory + (width * (height - 1) *4);
2030 textureRow = allocatedMemory;
2031 for (y = 0 ; y < height; y++) {
2032 for (i = 0; i < width; i++) {
2033 color = *((DWORD*)textureRow);
2034 fputc((color >> 16) & 0xFF, f); /* B */
2035 fputc((color >> 8) & 0xFF, f); /* G */
2036 fputc((color >> 0) & 0xFF, f); /* R */
2037 fputc((color >> 24) & 0xFF, f); /* A */
2040 /* take two rows of the pointer to the texture memory */
2042 (textureRow-= width << 3);
2045 TRACE("Closing file\n");
2049 IWineD3DSwapChain_Release(swapChain);
2051 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2055 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2056 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2057 This->Flags &= ~SFLAG_DIRTY;
2058 This->dirtyRect.left = This->currentDesc.Width;
2059 This->dirtyRect.top = This->currentDesc.Height;
2060 This->dirtyRect.right = 0;
2061 This->dirtyRect.bottom = 0;
2062 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2063 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2068 * Slightly inefficient way to handle multiple dirty rects but it works :)
2070 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2071 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2072 IWineD3DBaseTexture *baseTexture = NULL;
2073 This->Flags |= SFLAG_DIRTY;
2074 if (NULL != pDirtyRect) {
2075 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2076 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2077 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2078 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2080 This->dirtyRect.left = 0;
2081 This->dirtyRect.top = 0;
2082 This->dirtyRect.right = This->currentDesc.Width;
2083 This->dirtyRect.bottom = This->currentDesc.Height;
2085 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2086 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2087 /* if the container is a basetexture then mark it dirty. */
2088 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2089 TRACE("Passing to conatiner\n");
2090 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2091 IWineD3DBaseTexture_Release(baseTexture);
2096 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2097 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2099 TRACE("This %p, container %p\n", This, container);
2101 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2103 TRACE("Setting container to %p from %p\n", container, This->container);
2104 This->container = container;
2109 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2110 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2111 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2113 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2114 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2115 return WINED3DERR_INVALIDCALL;
2118 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2119 if (format == WINED3DFMT_UNKNOWN) {
2120 This->resource.size = 0;
2121 } else if (format == WINED3DFMT_DXT1) {
2122 /* DXT1 is half byte per pixel */
2123 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2125 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2126 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2127 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2129 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2130 This->resource.size *= This->pow2Height;
2134 /* Setup some glformat defaults */
2135 This->glDescription.glFormat = formatEntry->glFormat;
2136 This->glDescription.glFormatInternal = formatEntry->glInternal;
2137 This->glDescription.glType = formatEntry->glType;
2139 if (format != WINED3DFMT_UNKNOWN) {
2140 This->bytesPerPixel = formatEntry->bpp;
2141 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2143 This->bytesPerPixel = 0;
2147 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2149 This->resource.format = format;
2151 TRACE("(%p) : Size %d, pow2Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->pow2Size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
2156 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2157 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2159 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2160 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2161 ERR("Not supported on render targets\n");
2162 return WINED3DERR_INVALIDCALL;
2165 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2166 WARN("Surface is locked or the HDC is in use\n");
2167 return WINED3DERR_INVALIDCALL;
2170 if(Mem && Mem != This->resource.allocatedMemory) {
2172 /* Do I have to copy the old surface content? */
2173 if(This->Flags & SFLAG_DIBSECTION) {
2174 /* Release the DC. No need to hold the critical section for the update
2175 * Thread because this thread runs only on front buffers, but this method
2176 * fails for render targets in the check above.
2178 SelectObject(This->hDC, This->dib.holdbitmap);
2179 DeleteDC(This->hDC);
2180 /* Release the DIB section */
2181 DeleteObject(This->dib.DIBsection);
2182 This->dib.bitmap_data = NULL;
2183 This->resource.allocatedMemory = NULL;
2185 This->Flags &= ~SFLAG_DIBSECTION;
2186 } else if(!(This->Flags & SFLAG_USERPTR)) {
2187 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2189 This->resource.allocatedMemory = Mem;
2190 This->Flags |= SFLAG_USERPTR;
2191 } else if(This->Flags & SFLAG_USERPTR) {
2192 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2193 This->resource.allocatedMemory = NULL;
2194 This->Flags &= ~SFLAG_USERPTR;
2199 /* TODO: replace this function with context management routines */
2200 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2201 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2204 This->Flags |= SFLAG_INPBUFFER;
2206 This->Flags &= ~SFLAG_INPBUFFER;
2210 This->Flags |= SFLAG_INTEXTURE;
2212 This->Flags &= ~SFLAG_INTEXTURE;
2218 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2219 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2220 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2221 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2223 /* Flipping is only supported on RenderTargets */
2224 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2227 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2228 * FIXME("(%p) Target override is not supported by now\n", This);
2229 * Additionally, it isn't really possible to support triple-buffering
2230 * properly on opengl at all
2234 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2235 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2238 /* Not called from the VTable */
2239 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2241 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2242 IWineD3DSwapChainImpl *swapchain = NULL;
2243 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2246 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2248 /* Get the swapchain. One of the surfaces has to be a primary surface */
2249 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2250 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2252 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2253 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2254 else return WINED3DERR_INVALIDCALL;
2260 rect.x1 = DestRect->left;
2261 rect.y1 = DestRect->top;
2262 rect.x2 = DestRect->right;
2263 rect.y2 = DestRect->bottom;
2267 rect.x2 = This->currentDesc.Width;
2268 rect.y2 = This->currentDesc.Height;
2271 /* Half-life does a Blt from the back buffer to the front buffer,
2272 * Full surface size, no flags... Use present instead
2276 /* First, check if we can do a Flip */
2278 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2280 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2281 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2288 /* Check the Destination rect and the surface sizes */
2290 (rect.x1 == 0) && (rect.y1 == 0) &&
2291 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2292 (This->currentDesc.Width == Src->currentDesc.Width) &&
2293 (This->currentDesc.Height == Src->currentDesc.Height)) {
2294 /* These flags are unimportant for the flag check, remove them */
2296 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2297 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2299 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2301 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2302 * take very long, while a flip is fast.
2303 * This applies to Half-Life, which does such Blts every time it finished
2304 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2305 * menu. This is also used by all apps when they do windowed rendering
2307 * The problem is that flipping is not really the same as copying. After a
2308 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2309 * untouched. Therefore it's necessary to override the swap effect
2310 * and to set it back after the flip.
2313 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2315 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2316 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2317 NULL, NULL, 0, NULL);
2319 swapchain->presentParms.SwapEffect = orig_swap;
2326 /* Blt from texture to rendertarget? */
2327 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2328 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2330 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2331 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2332 float glTexCoord[4];
2334 DDCOLORKEY oldBltCKey = {0,0};
2335 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2336 GLint oldStencil, oldNVRegisterCombiners = 0;
2339 RECT SourceRectangle;
2342 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2345 SourceRectangle.left = SrcRect->left;
2346 SourceRectangle.right = SrcRect->right;
2347 SourceRectangle.top = SrcRect->top;
2348 SourceRectangle.bottom = SrcRect->bottom;
2350 SourceRectangle.left = 0;
2351 SourceRectangle.right = Src->currentDesc.Width;
2352 SourceRectangle.top = 0;
2353 SourceRectangle.bottom = Src->currentDesc.Height;
2356 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2357 /* Fall back to software */
2358 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2359 SourceRectangle.left, SourceRectangle.top,
2360 SourceRectangle.right, SourceRectangle.bottom);
2361 return WINED3DERR_INVALIDCALL;
2364 /* Color keying: Check if we have to do a color keyed blt,
2365 * and if not check if a color key is activated.
2367 oldCKey = Src->CKeyFlags;
2368 if(!(Flags & DDBLT_KEYSRC) &&
2369 Src->CKeyFlags & DDSD_CKSRCBLT) {
2370 /* Ok, the surface has a color key, but we shall not use it -
2371 * Deactivate it for now, LoadTexture will catch this
2373 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2377 if(Flags & DDBLT_KEYDEST) {
2378 oldBltCKey = This->SrcBltCKey;
2379 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2380 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2382 This->SrcBltCKey = This->DestBltCKey;
2383 } else if (Flags & DDBLT_KEYSRC)
2384 oldBltCKey = This->SrcBltCKey;
2386 /* Now load the surface */
2387 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2391 /* Save all the old stuff until we have a proper opengl state manager */
2392 oldLight = glIsEnabled(GL_LIGHTING);
2393 oldFog = glIsEnabled(GL_FOG);
2394 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2395 oldBlend = glIsEnabled(GL_BLEND);
2396 oldCull = glIsEnabled(GL_CULL_FACE);
2397 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2398 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2400 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2401 oldNVRegisterCombiners = glIsEnabled(GL_REGISTER_COMBINERS_NV);
2404 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2405 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2406 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2407 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2409 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2410 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2411 TRACE("Drawing to front buffer\n");
2412 glDrawBuffer(GL_FRONT);
2413 checkGLcall("glDrawBuffer GL_FRONT");
2416 /* Unbind the old texture */
2417 glBindTexture(GL_TEXTURE_2D, 0);
2418 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
2420 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2421 /* We use texture unit 0 for blts */
2422 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2423 checkGLcall("glActiveTextureARB");
2425 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2428 /* Disable some fancy graphics effects */
2429 glDisable(GL_LIGHTING);
2430 checkGLcall("glDisable GL_LIGHTING");
2431 glDisable(GL_DEPTH_TEST);
2432 checkGLcall("glDisable GL_DEPTH_TEST");
2434 checkGLcall("glDisable GL_FOG");
2435 glDisable(GL_BLEND);
2436 checkGLcall("glDisable GL_BLEND");
2437 glDisable(GL_CULL_FACE);
2438 checkGLcall("glDisable GL_CULL_FACE");
2439 glDisable(GL_STENCIL_TEST);
2440 checkGLcall("glDisable GL_STENCIL_TEST");
2441 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2442 glDisable(GL_REGISTER_COMBINERS_NV);
2443 checkGLcall("glDisable GL_REGISTER_COMBINERS_NV");
2446 /* Ok, we need 2d textures, but not 1D or 3D */
2447 glDisable(GL_TEXTURE_1D);
2448 checkGLcall("glDisable GL_TEXTURE_1D");
2449 glEnable(GL_TEXTURE_2D);
2450 checkGLcall("glEnable GL_TEXTURE_2D");
2451 glDisable(GL_TEXTURE_3D);
2452 checkGLcall("glDisable GL_TEXTURE_3D");
2454 /* Bind the texture */
2455 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2456 checkGLcall("glBindTexture");
2458 glEnable(GL_SCISSOR_TEST);
2460 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2462 /* No filtering for blts */
2463 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2465 checkGLcall("glTexParameteri");
2466 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2468 checkGLcall("glTexParameteri");
2469 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2470 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2471 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2472 checkGLcall("glTexEnvi");
2474 /* This is for color keying */
2475 if(Flags & DDBLT_KEYSRC) {
2476 glEnable(GL_ALPHA_TEST);
2477 checkGLcall("glEnable GL_ALPHA_TEST");
2478 glAlphaFunc(GL_NOTEQUAL, 0.0);
2479 checkGLcall("glAlphaFunc\n");
2481 glDisable(GL_ALPHA_TEST);
2482 checkGLcall("glDisable GL_ALPHA_TEST");
2485 /* Draw a textured quad
2487 myDevice->last_was_rhw = TRUE;
2488 /* Apply the projection matrix, it sets up orthogonal projection due to last_was_rhw */
2489 StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock);
2490 StateTable[STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))].apply(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), myDevice->stateBlock);
2491 /* That will reapply the projection matrix too */
2492 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL);
2496 glColor3d(1.0f, 1.0f, 1.0f);
2497 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2502 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2503 glVertex3f(rect.x1, rect.y2, 0.0);
2505 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2510 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2515 checkGLcall("glEnd");
2517 /* Unbind the texture */
2518 glBindTexture(GL_TEXTURE_2D, 0);
2519 checkGLcall("glEnable glBindTexture");
2521 /* Restore the old settings */
2523 glEnable(GL_LIGHTING);
2524 checkGLcall("glEnable GL_LIGHTING");
2528 checkGLcall("glEnable GL_FOG");
2531 glEnable(GL_DEPTH_TEST);
2532 checkGLcall("glEnable GL_DEPTH_TEST");
2536 checkGLcall("glEnable GL_BLEND");
2539 glEnable(GL_CULL_FACE);
2540 checkGLcall("glEnable GL_CULL_FACE");
2543 glEnable(GL_STENCIL_TEST);
2544 checkGLcall("glEnable GL_STENCIL_TEST");
2547 glDisable(GL_ALPHA_TEST);
2548 checkGLcall("glDisable GL_ALPHA_TEST");
2550 glEnable(GL_ALPHA_TEST);
2551 checkGLcall("glEnable GL_ALPHA_TEST");
2553 if (GL_SUPPORT(NV_REGISTER_COMBINERS) && oldNVRegisterCombiners) {
2554 glEnable(GL_REGISTER_COMBINERS_NV);
2555 checkGLcall("glEnable GL_REGISTER_COMBINERS_NV");
2558 glAlphaFunc(alphafunc, alpharef);
2559 checkGLcall("glAlphaFunc\n");
2561 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2562 glDrawBuffer(oldDraw);
2565 /* Restore the color key flags */
2566 if(oldCKey != Src->CKeyFlags) {
2567 Src->CKeyFlags = oldCKey;
2570 /* Restore the old color key */
2571 if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
2572 This->SrcBltCKey = oldBltCKey;
2576 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2577 This->Flags |= SFLAG_GLDIRTY;
2583 /* Blt from rendertarget to texture? */
2584 if( (SrcSurface == swapchain->frontBuffer) ||
2585 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2586 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2587 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2592 TRACE("Blt from rendertarget to texture\n");
2594 /* Call preload for the surface to make sure it isn't dirty */
2595 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2598 srect.x1 = SrcRect->left;
2599 srect.y1 = SrcRect->top;
2600 srect.x2 = SrcRect->right;
2601 srect.y2 = SrcRect->bottom;
2605 srect.x2 = Src->currentDesc.Width;
2606 srect.y2 = Src->currentDesc.Height;
2611 /* Bind the target texture */
2612 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2613 checkGLcall("glBindTexture");
2614 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2615 glReadBuffer(GL_BACK);
2617 glReadBuffer(GL_FRONT);
2619 checkGLcall("glReadBuffer");
2621 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2622 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2624 /* I have to process this row by row to swap the image,
2625 * otherwise it would be upside down, so streching in y direction
2626 * doesn't cost extra time
2628 * However, streching in x direction can be avoided if not necessary
2630 for(row = rect.y1; row < rect.y2; row++) {
2631 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2632 /* Well, that stuff works, but it's very slow.
2633 * find a better way instead
2636 for(col = rect.x1; col < rect.x2; col++) {
2637 glCopyTexSubImage2D(GL_TEXTURE_2D,
2639 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2640 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2644 glCopyTexSubImage2D(GL_TEXTURE_2D,
2646 rect.x1, rect.y2 + rect.y1 - row - 1, /* xoffset, yoffset */
2647 srect.x1, row - rect.y1,
2648 rect.x2-rect.x1, 1);
2652 vcheckGLcall("glCopyTexSubImage2D");
2655 if(!(This->Flags & SFLAG_DONOTFREE)) {
2656 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2657 This->resource.allocatedMemory = NULL;
2659 This->Flags |= SFLAG_GLDIRTY;
2667 if (Flags & DDBLT_COLORFILL) {
2668 /* This is easy to handle for the D3D Device... */
2670 IWineD3DSwapChainImpl *implSwapChain;
2672 TRACE("Colorfill\n");
2674 /* The color as given in the Blt function is in the format of the frame-buffer...
2675 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2677 if (This->resource.format == WINED3DFMT_P8) {
2678 if (This->palette) {
2679 color = ((0xFF000000) |
2680 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2681 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2682 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2687 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2688 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2691 color = ((0xFF000000) |
2692 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2693 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2694 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2697 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2698 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2699 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2701 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2702 color = DDBltFx->u5.dwFillColor;
2705 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2706 return WINED3DERR_INVALIDCALL;
2709 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2710 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2711 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2712 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2713 glDrawBuffer(GL_BACK);
2714 checkGLcall("glDrawBuffer(GL_BACK)");
2716 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2717 glDrawBuffer(GL_FRONT);
2718 checkGLcall("glDrawBuffer(GL_FRONT)");
2721 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2722 return WINED3DERR_INVALIDCALL;
2725 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2727 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2728 1 /* Number of rectangles */,
2730 WINED3DCLEAR_TARGET,
2735 /* Restore the original draw buffer */
2736 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2737 glDrawBuffer(GL_BACK);
2738 vcheckGLcall("glDrawBuffer");
2744 /* Default: Fall back to the generic blt */
2745 return WINED3DERR_INVALIDCALL;
2748 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2749 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2750 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2751 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2752 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2754 /* Special cases for RenderTargets */
2755 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2756 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2757 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2760 /* For the rest call the X11 surface implementation.
2761 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2762 * other Blts are rather rare
2764 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2767 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2768 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2769 TRACE("(%p)->(%x)\n", This, Flags);
2774 case DDGBS_ISBLTDONE:
2778 return DDERR_INVALIDPARAMS;
2782 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2783 /* XXX: DDERR_INVALIDSURFACETYPE */
2785 TRACE("(%p)->(%08x)\n",iface,Flags);
2788 case DDGFS_ISFLIPDONE:
2792 return DDERR_INVALIDPARAMS;
2796 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2797 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2798 TRACE("(%p)\n", This);
2800 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2803 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2804 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2805 TRACE("(%p)\n", This);
2807 /* So far we don't lose anything :) */
2808 This->Flags &= ~SFLAG_LOST;
2812 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2813 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2814 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2815 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2817 /* Special cases for RenderTargets */
2818 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2819 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2821 RECT SrcRect, DstRect;
2825 SrcRect.left = rsrc->left;
2826 SrcRect.top= rsrc->top;
2827 SrcRect.bottom = rsrc->bottom;
2828 SrcRect.right = rsrc->right;
2832 SrcRect.right = srcImpl->currentDesc.Width;
2833 SrcRect.bottom = srcImpl->currentDesc.Height;
2836 DstRect.left = dstx;
2838 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2839 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2841 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2842 if(trans & DDBLTFAST_SRCCOLORKEY)
2843 Flags |= DDBLT_KEYSRC;
2844 if(trans & DDBLTFAST_DESTCOLORKEY)
2845 Flags |= DDBLT_KEYDEST;
2846 if(trans & DDBLTFAST_WAIT)
2847 Flags |= DDBLT_WAIT;
2848 if(trans & DDBLTFAST_DONOTWAIT)
2849 Flags |= DDBLT_DONOTWAIT;
2851 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2855 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2858 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2859 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2860 TRACE("(%p)->(%p)\n", This, Pal);
2862 *Pal = (IWineD3DPalette *) This->palette;
2866 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2867 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2869 IWineD3DPaletteImpl *pal = This->palette;
2871 TRACE("(%p)\n", This);
2873 if(This->resource.format == WINED3DFMT_P8 ||
2874 This->resource.format == WINED3DFMT_A8P8)
2876 TRACE("Dirtifying surface\n");
2877 This->Flags |= SFLAG_DIRTY;
2880 if(This->Flags & SFLAG_DIBSECTION) {
2881 TRACE("(%p): Updating the hdc's palette\n", This);
2882 for (n=0; n<256; n++) {
2884 col[n].rgbRed = pal->palents[n].peRed;
2885 col[n].rgbGreen = pal->palents[n].peGreen;
2886 col[n].rgbBlue = pal->palents[n].peBlue;
2888 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2889 /* Use the default device palette */
2890 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2891 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2892 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2894 col[n].rgbReserved = 0;
2896 SetDIBColorTable(This->hDC, 0, 256, col);
2902 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2903 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2904 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2905 TRACE("(%p)->(%p)\n", This, Pal);
2907 if(This->palette != NULL)
2908 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2909 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2911 if(PalImpl != NULL) {
2912 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2913 /* Set the device's main palette if the palette
2914 * wasn't a primary palette before
2916 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2917 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2920 for(i=0; i < 256; i++) {
2921 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2925 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2928 This->palette = PalImpl;
2930 return IWineD3DSurface_RealizePalette(iface);
2933 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2934 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2935 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
2937 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2938 FIXME(" colorkey value not supported (%08x) !\n", Flags);
2939 return DDERR_INVALIDPARAMS;
2942 /* Dirtify the surface, but only if a key was changed */
2944 switch (Flags & ~DDCKEY_COLORSPACE) {
2945 case DDCKEY_DESTBLT:
2946 This->DestBltCKey = *CKey;
2947 This->CKeyFlags |= DDSD_CKDESTBLT;
2950 case DDCKEY_DESTOVERLAY:
2951 This->DestOverlayCKey = *CKey;
2952 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2955 case DDCKEY_SRCOVERLAY:
2956 This->SrcOverlayCKey = *CKey;
2957 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2961 This->SrcBltCKey = *CKey;
2962 This->CKeyFlags |= DDSD_CKSRCBLT;
2967 switch (Flags & ~DDCKEY_COLORSPACE) {
2968 case DDCKEY_DESTBLT:
2969 This->CKeyFlags &= ~DDSD_CKDESTBLT;
2972 case DDCKEY_DESTOVERLAY:
2973 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
2976 case DDCKEY_SRCOVERLAY:
2977 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
2981 This->CKeyFlags &= ~DDSD_CKSRCBLT;
2989 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
2990 /** Check against the maximum texture sizes supported by the video card **/
2991 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2993 TRACE("%p\n", This);
2994 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
2995 /* one of three options
2996 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)
2997 2: Set the texture to the maxium size (bad idea)
2998 3: WARN and return WINED3DERR_NOTAVAILABLE;
2999 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.
3001 WARN("(%p) Creating an oversized surface\n", This);
3002 This->Flags |= SFLAG_OVERSIZE;
3004 /* This will be initialized on the first blt */
3005 This->glRect.left = 0;
3006 This->glRect.top = 0;
3007 This->glRect.right = 0;
3008 This->glRect.bottom = 0;
3010 /* No oversize, gl rect is the full texture size */
3011 This->Flags &= ~SFLAG_OVERSIZE;
3012 This->glRect.left = 0;
3013 This->glRect.top = 0;
3014 This->glRect.right = This->pow2Width;
3015 This->glRect.bottom = This->pow2Height;
3021 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3022 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3024 TRACE("(%p)\n", This);
3026 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3027 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3028 ie pitch = (width/4) * bytes per block */
3029 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3030 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3031 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3032 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3033 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3035 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3036 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3037 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3039 ret = This->bytesPerPixel * This->pow2Width;
3041 /* Surfaces are 32 bit aligned */
3042 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3044 TRACE("(%p) Returning %d\n", This, ret);
3048 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3049 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3051 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3053 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3055 TRACE("(%p): Not an overlay surface\n", This);
3056 return DDERR_NOTAOVERLAYSURFACE;
3062 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3063 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3065 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3067 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3069 TRACE("(%p): Not an overlay surface\n", This);
3070 return DDERR_NOTAOVERLAYSURFACE;
3076 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3077 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3078 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3080 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3082 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3084 TRACE("(%p): Not an overlay surface\n", This);
3085 return DDERR_NOTAOVERLAYSURFACE;
3091 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3092 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3093 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3094 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3096 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3098 TRACE("(%p): Not an overlay surface\n", This);
3099 return DDERR_NOTAOVERLAYSURFACE;
3105 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3108 IWineD3DSurfaceImpl_QueryInterface,
3109 IWineD3DSurfaceImpl_AddRef,
3110 IWineD3DSurfaceImpl_Release,
3111 /* IWineD3DResource */
3112 IWineD3DSurfaceImpl_GetParent,
3113 IWineD3DSurfaceImpl_GetDevice,
3114 IWineD3DSurfaceImpl_SetPrivateData,
3115 IWineD3DSurfaceImpl_GetPrivateData,
3116 IWineD3DSurfaceImpl_FreePrivateData,
3117 IWineD3DSurfaceImpl_SetPriority,
3118 IWineD3DSurfaceImpl_GetPriority,
3119 IWineD3DSurfaceImpl_PreLoad,
3120 IWineD3DSurfaceImpl_GetType,
3121 /* IWineD3DSurface */
3122 IWineD3DSurfaceImpl_GetContainer,
3123 IWineD3DSurfaceImpl_GetDesc,
3124 IWineD3DSurfaceImpl_LockRect,
3125 IWineD3DSurfaceImpl_UnlockRect,
3126 IWineD3DSurfaceImpl_GetDC,
3127 IWineD3DSurfaceImpl_ReleaseDC,
3128 IWineD3DSurfaceImpl_Flip,
3129 IWineD3DSurfaceImpl_Blt,
3130 IWineD3DSurfaceImpl_GetBltStatus,
3131 IWineD3DSurfaceImpl_GetFlipStatus,
3132 IWineD3DSurfaceImpl_IsLost,
3133 IWineD3DSurfaceImpl_Restore,
3134 IWineD3DSurfaceImpl_BltFast,
3135 IWineD3DSurfaceImpl_GetPalette,
3136 IWineD3DSurfaceImpl_SetPalette,
3137 IWineD3DSurfaceImpl_RealizePalette,
3138 IWineD3DSurfaceImpl_SetColorKey,
3139 IWineD3DSurfaceImpl_GetPitch,
3140 IWineD3DSurfaceImpl_SetMem,
3141 IWineD3DSurfaceImpl_SetOverlayPosition,
3142 IWineD3DSurfaceImpl_GetOverlayPosition,
3143 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3144 IWineD3DSurfaceImpl_UpdateOverlay,
3146 IWineD3DSurfaceImpl_CleanDirtyRect,
3147 IWineD3DSurfaceImpl_AddDirtyRect,
3148 IWineD3DSurfaceImpl_LoadTexture,
3149 IWineD3DSurfaceImpl_SaveSnapshot,
3150 IWineD3DSurfaceImpl_SetContainer,
3151 IWineD3DSurfaceImpl_SetPBufferState,
3152 IWineD3DSurfaceImpl_SetGlTextureDesc,
3153 IWineD3DSurfaceImpl_GetGlDesc,
3154 IWineD3DSurfaceImpl_GetData,
3155 IWineD3DSurfaceImpl_SetFormat,
3156 IWineD3DSurfaceImpl_PrivateSetup