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 if (IsEqualGUID(riid, &IID_IUnknown)
193 || IsEqualGUID(riid, &IID_IWineD3DBase)
194 || IsEqualGUID(riid, &IID_IWineD3DResource)
195 || IsEqualGUID(riid, &IID_IWineD3DSurface)) {
196 IUnknown_AddRef((IUnknown*)iface);
201 return E_NOINTERFACE;
204 ULONG WINAPI IWineD3DSurfaceImpl_AddRef(IWineD3DSurface *iface) {
205 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
206 ULONG ref = InterlockedIncrement(&This->resource.ref);
207 TRACE("(%p) : AddRef increasing from %d\n", This,ref - 1);
211 ULONG WINAPI IWineD3DSurfaceImpl_Release(IWineD3DSurface *iface) {
212 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
213 ULONG ref = InterlockedDecrement(&This->resource.ref);
214 TRACE("(%p) : Releasing from %d\n", This, ref + 1);
216 IWineD3DDeviceImpl *device = (IWineD3DDeviceImpl *) This->resource.wineD3DDevice;
217 TRACE("(%p) : cleaning up\n", This);
218 if (This->glDescription.textureName != 0) { /* release the openGL texture.. */
220 TRACE("Deleting texture %d\n", This->glDescription.textureName);
221 glDeleteTextures(1, &This->glDescription.textureName);
225 if(This->Flags & SFLAG_DIBSECTION) {
227 SelectObject(This->hDC, This->dib.holdbitmap);
229 /* Release the DIB section */
230 DeleteObject(This->dib.DIBsection);
231 This->dib.bitmap_data = NULL;
232 This->resource.allocatedMemory = NULL;
234 if(This->Flags & SFLAG_USERPTR) IWineD3DSurface_SetMem(iface, NULL);
236 IWineD3DResourceImpl_CleanUp((IWineD3DResource *)iface);
237 if(iface == device->ddraw_primary)
238 device->ddraw_primary = NULL;
240 TRACE("(%p) Released\n", This);
241 HeapFree(GetProcessHeap(), 0, This);
247 /* ****************************************************
248 IWineD3DSurface IWineD3DResource parts follow
249 **************************************************** */
250 HRESULT WINAPI IWineD3DSurfaceImpl_GetDevice(IWineD3DSurface *iface, IWineD3DDevice** ppDevice) {
251 return IWineD3DResourceImpl_GetDevice((IWineD3DResource *)iface, ppDevice);
254 HRESULT WINAPI IWineD3DSurfaceImpl_SetPrivateData(IWineD3DSurface *iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
255 return IWineD3DResourceImpl_SetPrivateData((IWineD3DResource *)iface, refguid, pData, SizeOfData, Flags);
258 HRESULT WINAPI IWineD3DSurfaceImpl_GetPrivateData(IWineD3DSurface *iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
259 return IWineD3DResourceImpl_GetPrivateData((IWineD3DResource *)iface, refguid, pData, pSizeOfData);
262 HRESULT WINAPI IWineD3DSurfaceImpl_FreePrivateData(IWineD3DSurface *iface, REFGUID refguid) {
263 return IWineD3DResourceImpl_FreePrivateData((IWineD3DResource *)iface, refguid);
266 DWORD WINAPI IWineD3DSurfaceImpl_SetPriority(IWineD3DSurface *iface, DWORD PriorityNew) {
267 return IWineD3DResourceImpl_SetPriority((IWineD3DResource *)iface, PriorityNew);
270 DWORD WINAPI IWineD3DSurfaceImpl_GetPriority(IWineD3DSurface *iface) {
271 return IWineD3DResourceImpl_GetPriority((IWineD3DResource *)iface);
274 void WINAPI IWineD3DSurfaceImpl_PreLoad(IWineD3DSurface *iface) {
275 /* TODO: re-write the way textures and managed,
276 * use a 'opengl context manager' to manage RenderTarget surfaces
277 ** *********************************************************/
279 /* TODO: check for locks */
280 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
281 IWineD3DBaseTexture *baseTexture = NULL;
282 TRACE("(%p)Checking to see if the container is a base texture\n", This);
283 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
284 TRACE("Passing to conatiner\n");
285 IWineD3DBaseTexture_PreLoad(baseTexture);
286 IWineD3DBaseTexture_Release(baseTexture);
288 TRACE("(%p) : About to load surface\n", This);
290 #if 0 /* TODO: context manager support */
291 IWineD3DContextManager_PushState(This->contextManager, GL_TEXTURE_2D, ENABLED, NOW /* make sure the state is applied now */);
293 glEnable(This->glDescription.target);/* make sure texture support is enabled in this context */
294 if (!This->glDescription.level) {
295 if (!This->glDescription.textureName) {
296 glGenTextures(1, &This->glDescription.textureName);
297 checkGLcall("glGenTextures");
298 TRACE("Surface %p given name %d\n", This, This->glDescription.textureName);
300 glBindTexture(This->glDescription.target, This->glDescription.textureName);
301 checkGLcall("glBindTexture");
302 IWineD3DSurface_LoadTexture(iface);
303 /* This is where we should be reducing the amount of GLMemoryUsed */
304 } else if (This->glDescription.textureName) { /* NOTE: the level 0 surface of a mpmapped texture must be loaded first! */
305 /* assume this is a coding error not a real error for now */
306 FIXME("Mipmap surface has a glTexture bound to it!\n");
308 if (This->resource.pool == WINED3DPOOL_DEFAULT) {
309 /* Tell opengl to try and keep this texture in video ram (well mostly) */
312 glPrioritizeTextures(1, &This->glDescription.textureName, &tmp);
314 /* TODO: disable texture support, if it wastn't enabled when we entered. */
315 #if 0 /* TODO: context manager support */
316 IWineD3DContextManager_PopState(This->contextManager, GL_TEXTURE_2D, DISABLED,DELAYED
317 /* we don't care when the state is disabled(if atall) */);
324 WINED3DRESOURCETYPE WINAPI IWineD3DSurfaceImpl_GetType(IWineD3DSurface *iface) {
325 TRACE("(%p) : calling resourceimpl_GetType\n", iface);
326 return IWineD3DResourceImpl_GetType((IWineD3DResource *)iface);
329 HRESULT WINAPI IWineD3DSurfaceImpl_GetParent(IWineD3DSurface *iface, IUnknown **pParent) {
330 TRACE("(%p) : calling resourceimpl_GetParent\n", iface);
331 return IWineD3DResourceImpl_GetParent((IWineD3DResource *)iface, pParent);
334 /* ******************************************************
335 IWineD3DSurface IWineD3DSurface parts follow
336 ****************************************************** */
338 HRESULT WINAPI IWineD3DSurfaceImpl_GetContainer(IWineD3DSurface* iface, REFIID riid, void** ppContainer) {
339 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
340 IWineD3DBase *container = 0;
342 TRACE("(This %p, riid %s, ppContainer %p)\n", This, debugstr_guid(riid), ppContainer);
345 ERR("Called without a valid ppContainer.\n");
349 * If the surface is created using CreateImageSurface/CreateOffscreenPlainSurface, CreateRenderTarget,
350 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
351 * GetContainer will return the Direct3D device used to create the surface.
353 if (This->container) {
354 container = This->container;
356 container = (IWineD3DBase *)This->resource.wineD3DDevice;
359 TRACE("Relaying to QueryInterface\n");
360 return IUnknown_QueryInterface(container, riid, ppContainer);
363 HRESULT WINAPI IWineD3DSurfaceImpl_GetDesc(IWineD3DSurface *iface, WINED3DSURFACE_DESC *pDesc) {
364 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
366 TRACE("(%p) : copying into %p\n", This, pDesc);
367 if(pDesc->Format != NULL) *(pDesc->Format) = This->resource.format;
368 if(pDesc->Type != NULL) *(pDesc->Type) = This->resource.resourceType;
369 if(pDesc->Usage != NULL) *(pDesc->Usage) = This->resource.usage;
370 if(pDesc->Pool != NULL) *(pDesc->Pool) = This->resource.pool;
371 if(pDesc->Size != NULL) *(pDesc->Size) = This->resource.size; /* dx8 only */
372 if(pDesc->MultiSampleType != NULL) *(pDesc->MultiSampleType) = This->currentDesc.MultiSampleType;
373 if(pDesc->MultiSampleQuality != NULL) *(pDesc->MultiSampleQuality) = This->currentDesc.MultiSampleQuality;
374 if(pDesc->Width != NULL) *(pDesc->Width) = This->currentDesc.Width;
375 if(pDesc->Height != NULL) *(pDesc->Height) = This->currentDesc.Height;
379 void WINAPI IWineD3DSurfaceImpl_SetGlTextureDesc(IWineD3DSurface *iface, UINT textureName, int target) {
380 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
381 TRACE("(%p) : setting textureName %u, target %i\n", This, textureName, target);
382 if (This->glDescription.textureName == 0 && textureName != 0) {
383 This->Flags |= SFLAG_DIRTY;
384 IWineD3DSurface_AddDirtyRect(iface, NULL);
386 This->glDescription.textureName = textureName;
387 This->glDescription.target = target;
390 void WINAPI IWineD3DSurfaceImpl_GetGlDesc(IWineD3DSurface *iface, glDescriptor **glDescription) {
391 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
392 TRACE("(%p) : returning %p\n", This, &This->glDescription);
393 *glDescription = &This->glDescription;
396 /* TODO: think about moving this down to resource? */
397 const void *WINAPI IWineD3DSurfaceImpl_GetData(IWineD3DSurface *iface) {
398 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
399 /* This should only be called for sysmem textures, it may be a good idea to extend this to all pools at some point in the futture */
400 if (This->resource.pool != WINED3DPOOL_SYSTEMMEM) {
401 FIXME(" (%p)Attempting to get system memory for a non-system memory texture\n", iface);
403 return (CONST void*)(This->resource.allocatedMemory);
406 static void read_from_framebuffer(IWineD3DSurfaceImpl *This, CONST RECT *rect, void *dest, UINT pitch) {
412 switch(This->resource.format)
416 /* GL can't return palettized data, so read ARGB pixels into a
417 * separate block of memory and convert them into palettized format
418 * in software. Slow, but if the app means to use palettized render
419 * targets and locks it...
421 * Use GL_RGB, GL_UNSIGNED_BYTE to read the surface for performance reasons
422 * Don't use GL_BGR as in the WINED3DFMT_R8G8B8 case, instead watch out
423 * for the color channels when palettizing the colors.
426 type = GL_UNSIGNED_BYTE;
428 mem = HeapAlloc(GetProcessHeap(), 0, (rect->bottom - rect->top) * pitch);
430 ERR("Out of memory\n");
438 fmt = This->glDescription.glFormat;
439 type = This->glDescription.glType;
442 if (rect->left == 0 &&
443 rect->right == This->currentDesc.Width ) {
444 BYTE *row, *top, *bottom;
447 glReadPixels(0, rect->top,
448 This->currentDesc.Width,
449 rect->bottom - rect->top,
454 /* glReadPixels returns the image upside down, and there is no way to prevent this.
455 Flip the lines in software */
456 row = HeapAlloc(GetProcessHeap(), 0, pitch);
458 ERR("Out of memory\n");
462 bottom = ((BYTE *) mem) + pitch * ( rect->bottom - rect->top - 1);
463 for(i = 0; i < (rect->bottom - rect->top) / 2; i++) {
464 memcpy(row, top, pitch);
465 memcpy(top, bottom, pitch);
466 memcpy(bottom, row, pitch);
470 HeapFree(GetProcessHeap(), 0, row);
472 if(This->lockedRect.top == 0 && This->lockedRect.bottom == This->currentDesc.Height) {
473 This->Flags &= ~SFLAG_GLDIRTY;
476 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
477 glReadPixels(rect->left,
478 rect->bottom - j - 1,
479 rect->right - rect->left,
483 (char *)mem + (pitch * (j-rect->top)));
487 vcheckGLcall("glReadPixels");
489 if(This->resource.format == WINED3DFMT_P8) {
491 DWORD width = pitch / 3;
494 pal = This->palette->palents;
496 pal = This->resource.wineD3DDevice->palettes[This->resource.wineD3DDevice->currentPalette];
499 for(y = rect->top; y < rect->bottom; y++) {
500 for(x = rect->left; x < rect->right; x++) {
501 /* start lines pixels */
502 BYTE *blue = (BYTE *) ((BYTE *) mem) + y * pitch + x * (sizeof(BYTE) * 3);
503 BYTE *green = blue + 1;
504 BYTE *red = green + 1;
506 for(c = 0; c < 256; c++) {
507 if(*red == pal[c].peRed &&
508 *green == pal[c].peGreen &&
509 *blue == pal[c].peBlue)
511 *((BYTE *) dest + y * width + x) = c;
517 HeapFree(GetProcessHeap(), 0, mem);
521 static HRESULT WINAPI IWineD3DSurfaceImpl_LockRect(IWineD3DSurface *iface, WINED3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
522 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
523 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
524 IWineD3DSwapChainImpl *swapchain = NULL;
525 static UINT messages = 0; /* holds flags to disable fixme messages */
526 BOOL backbuf = FALSE;
528 /* fixme: should we really lock as such? */
529 if((This->Flags & (SFLAG_INTEXTURE | SFLAG_INPBUFFER)) ==
530 (SFLAG_INTEXTURE | SFLAG_INPBUFFER) ) {
531 FIXME("Warning: Surface is in texture memory or pbuffer\n");
532 This->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INPBUFFER);
535 if (!(This->Flags & SFLAG_LOCKABLE)) {
536 /* Note: UpdateTextures calls CopyRects which calls this routine to populate the
537 texture regions, and since the destination is an unlockable region we need
539 TRACE("Warning: trying to lock unlockable surf@%p\n", This);
540 /*return WINED3DERR_INVALIDCALL; */
543 if (This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
544 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
546 if (swapchain != NULL || iface == myDevice->render_targets[0] || iface == myDevice->depthStencilBuffer) {
547 if(swapchain != NULL) {
549 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
550 if(iface == swapchain->backBuffer[i]) {
557 TRACE("(%p, backBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
558 } else if (swapchain != NULL && iface == swapchain->frontBuffer) {
559 TRACE("(%p, frontBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
560 } else if (iface == myDevice->render_targets[0]) {
561 TRACE("(%p, renderTarget) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
562 } else if (iface == myDevice->depthStencilBuffer) {
563 TRACE("(%p, stencilBuffer) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
566 if (NULL != swapchain) {
567 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
572 TRACE("(%p) : rect@%p flags(%08x), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->resource.allocatedMemory);
575 pLockedRect->Pitch = IWineD3DSurface_GetPitch(iface);
578 pLockedRect->pBits = This->resource.allocatedMemory;
579 This->lockedRect.left = 0;
580 This->lockedRect.top = 0;
581 This->lockedRect.right = This->currentDesc.Width;
582 This->lockedRect.bottom = This->currentDesc.Height;
583 TRACE("Locked Rect (%p) = l %d, t %d, r %d, b %d\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
585 TRACE("Lock Rect (%p) = l %d, t %d, r %d, b %d\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
587 if ((pRect->top < 0) ||
589 (pRect->left >= pRect->right) ||
590 (pRect->top >= pRect->bottom) ||
591 (pRect->right > This->currentDesc.Width) ||
592 (pRect->bottom > This->currentDesc.Height))
594 WARN(" Invalid values in pRect !!!\n");
595 return D3DERR_INVALIDCALL;
598 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
599 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
601 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
603 This->lockedRect.left = pRect->left;
604 This->lockedRect.top = pRect->top;
605 This->lockedRect.right = pRect->right;
606 This->lockedRect.bottom = pRect->bottom;
609 if (This->Flags & SFLAG_NONPOW2) {
610 TRACE("Locking non-power 2 texture\n");
613 if (0 == This->resource.usage || This->resource.usage & WINED3DUSAGE_DYNAMIC) {
614 /* classic surface TODO: non 2d surfaces?
615 These resources may be POOL_SYSTEMMEM, so they must not access the device */
616 TRACE("locking an ordinarary surface\n");
617 /* Check to see if memory has already been allocated from the surface*/
618 if ((NULL == This->resource.allocatedMemory) ||
619 (This->Flags & SFLAG_GLDIRTY) ){ /* TODO: check to see if an update has been performed on the surface (an update could just clobber allocatedMemory */
620 /* Non-system memory surfaces */
622 This->Flags &= ~SFLAG_GLDIRTY;
624 /*Surface has no memory currently allocated to it!*/
625 TRACE("(%p) Locking rect\n" , This);
626 if(!This->resource.allocatedMemory) {
627 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 , This->pow2Size);
629 if (0 != This->glDescription.textureName) {
630 /* Now I have to copy thing bits back */
631 This->Flags |= SFLAG_ACTIVELOCK; /* When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory */
632 /* TODO: make activeLock a bit more intelligent, maybe implement a method to purge the texture memory. */
634 /* Make sure that a proper texture unit is selected, bind the texture and dirtify the sampler to restore the texture on the next draw */
635 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
637 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
638 checkGLcall("glActiveTextureARB");
641 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
642 IWineD3DSurface_PreLoad(iface);
644 surface_download_data(This);
646 } else { /* Nothing to do */
647 TRACE("Memory %p already allocted for texture\n", This->resource.allocatedMemory);
651 pLockedRect->pBits = This->resource.allocatedMemory;
653 if (This->resource.format == WINED3DFMT_DXT1) { /* DXT1 is half byte per pixel */
654 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + ((pRect->left * This->bytesPerPixel / 2));
656 pLockedRect->pBits = This->resource.allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
660 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage ){ /* render surfaces */
661 if((!(Flags&WINED3DLOCK_DISCARD) && (This->Flags & SFLAG_GLDIRTY)) || !This->resource.allocatedMemory) {
664 BOOL notInContext = FALSE;
665 IWineD3DSwapChainImpl *targetSwapChain = NULL;
671 * for render->surface copy begin to begin of allocatedMemory
672 * unlock can be more easy
675 TRACE("locking a render target\n");
677 if (This->resource.allocatedMemory == NULL)
678 This->resource.allocatedMemory = HeapAlloc(GetProcessHeap() ,0 ,This->resource.size);
680 This->Flags |= SFLAG_ACTIVELOCK; /*When this flag is set to true, loading the surface again won't free THis->resource.allocatedMemory*/
681 pLockedRect->pBits = This->resource.allocatedMemory;
684 vcheckGLcall("glFlush");
685 glGetIntegerv(GL_READ_BUFFER, &prev_read);
686 vcheckGLcall("glIntegerv");
687 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
688 vcheckGLcall("glIntegerv");
690 /* Here's what we have to do:
691 See if the swapchain has the same context as the renderTarget or the surface is the render target.
692 Otherwise, see if were sharing a context with the implicit swapchain (because we're using a shared context model!)
693 and use the front back buffer as required.
694 if not, we need to switch contexts and then switchback at the end.
696 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
697 IWineD3DSurface_GetContainer(myDevice->render_targets[0], &IID_IWineD3DSwapChain, (void **)&targetSwapChain);
699 /* NOTE: In a shared context environment the renderTarget will use the same context as the implicit swapchain (we're not in a shared environment yet! */
700 if ((swapchain == targetSwapChain && targetSwapChain != NULL) || iface == myDevice->render_targets[0]) {
701 if (swapchain && iface == swapchain->frontBuffer) {
702 TRACE("locking front\n");
703 glReadBuffer(GL_FRONT);
705 else if (iface == myDevice->render_targets[0] || backbuf) {
706 TRACE("locking back buffer\n");
707 glReadBuffer(GL_BACK);
708 } else if (iface == myDevice->depthStencilBuffer) {
709 FIXME("Stencil Buffer lock unsupported for now\n");
711 FIXME("(%p) Shouldn't have got here!\n", This);
712 glReadBuffer(GL_BACK);
714 } else if (swapchain != NULL) {
715 IWineD3DSwapChainImpl *implSwapChain;
716 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
717 if (swapchain->glCtx == implSwapChain->render_ctx && swapchain->drawable == implSwapChain->win) {
718 /* This will fail for the implicit swapchain, which is why there needs to be a context manager */
720 glReadBuffer(GL_BACK);
721 } else if (iface == swapchain->frontBuffer) {
722 glReadBuffer(GL_FRONT);
723 } else if (iface == myDevice->depthStencilBuffer) {
724 FIXME("Stencil Buffer lock unsupported for now\n");
726 FIXME("Should have got here!\n");
727 glReadBuffer(GL_BACK);
730 /* We need to switch contexts to be able to read the buffer!!! */
731 FIXME("The buffer requested isn't in the current openGL context\n");
733 /* TODO: check the contexts, to see if were shared with the current context */
735 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
737 if (swapchain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
738 if (targetSwapChain != NULL) IWineD3DSwapChain_Release((IWineD3DSwapChain *)targetSwapChain);
740 /** the depth stencil in openGL has a format of GL_FLOAT
741 * which should be good for WINED3DFMT_D16_LOCKABLE
743 * it is unclear what format the stencil buffer is in except.
744 * 'Each index is converted to fixed point...
745 * If GL_MAP_STENCIL is GL_TRUE, indices are replaced by their
746 * mappings in the table GL_PIXEL_MAP_S_TO_S.
747 * glReadPixels(This->lockedRect.left,
748 * This->lockedRect.bottom - j - 1,
749 * This->lockedRect.right - This->lockedRect.left,
751 * GL_DEPTH_COMPONENT,
753 * (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
754 *****************************************/
755 if (!notInContext) { /* Only read the buffer if it's in the current context */
756 switch(wined3d_settings.rendertargetlock_mode) {
760 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
765 read_from_framebuffer(This, &This->lockedRect, pLockedRect->pBits, pLockedRect->Pitch);
766 FIXME("Reading from render target with a texture isn't implemented yet, falling back to framebuffer reading\n");
771 static BOOL warned = FALSE;
773 ERR("Application tries to lock the render target, but render target locking is disabled\n");
780 TRACE("Resetting buffer\n");
782 glReadBuffer(prev_read);
783 vcheckGLcall("glReadBuffer");
787 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
790 FIXME("TODO stencil depth surface locking surf%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
793 glReadPixels(This->lockedRect.left,
794 This->lockedRect.bottom - j - 1,
795 This->lockedRect.right - This->lockedRect.left,
797 GL_STENCIL_INDEX or GL_DEPTH_COMPONENT
804 FIXME("unsupported locking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
807 if (Flags & (WINED3DLOCK_NO_DIRTY_UPDATE | WINED3DLOCK_READONLY)) {
810 IWineD3DBaseTexture *pBaseTexture;
813 * as seen in msdn docs
815 IWineD3DSurface_AddDirtyRect(iface, &This->lockedRect);
817 /** Dirtify Container if needed */
818 if (WINED3D_OK == IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&pBaseTexture) && pBaseTexture != NULL) {
819 TRACE("Making container dirty\n");
820 IWineD3DBaseTexture_SetDirty(pBaseTexture, TRUE);
821 IWineD3DBaseTexture_Release(pBaseTexture);
823 TRACE("Surface is standalone, no need to dirty the container\n");
827 /* Performance optimization: Count how often a surface is locked, if it is locked regularly do not throw away the system memory copy.
828 * This avoids the need to download the surface from opengl all the time. The surface is still downloaded if the opengl texture is
831 if(!(This->Flags & SFLAG_DYNLOCK)) {
833 /* MAXLOCKCOUNT is defined in wined3d_private.h */
834 if(This->lockCount > MAXLOCKCOUNT) {
835 TRACE("Surface is locked regularily, not freeing the system memory copy any more\n");
836 This->Flags |= SFLAG_DYNLOCK;
840 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Flags & SFLAG_DIRTY ? 0 : 1);
842 This->Flags |= SFLAG_LOCKED;
846 static void flush_to_framebuffer_drawpixels(IWineD3DSurfaceImpl *This) {
848 GLint prev_rasterpos[4];
850 BOOL storechanged = FALSE;
854 glDisable(GL_TEXTURE_2D);
855 vcheckGLcall("glDisable(GL_TEXTURE_2D)");
856 glDisable(GL_TEXTURE_1D);
857 vcheckGLcall("glDisable(GL_TEXTURE_1D)");
860 vcheckGLcall("glFlush");
861 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
862 vcheckGLcall("glIntegerv");
863 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
864 vcheckGLcall("glIntegerv");
865 glPixelZoom(1.0, -1.0);
866 vcheckGLcall("glPixelZoom");
868 /* If not fullscreen, we need to skip a number of bytes to find the next row of data */
869 glGetIntegerv(GL_UNPACK_ROW_LENGTH, &skipBytes);
870 glPixelStorei(GL_UNPACK_ROW_LENGTH, This->currentDesc.Width);
872 glRasterPos3i(This->lockedRect.left, This->lockedRect.top, 1);
873 vcheckGLcall("glRasterPos2f");
875 /* Some drivers(radeon dri, others?) don't like exceptions during
876 * glDrawPixels. If the surface is a DIB section, it might be in GDIMode
877 * after ReleaseDC. Reading it will cause an exception, which x11drv will
878 * catch to put the dib section in InSync mode, which leads to a crash
879 * and a blocked x server on my radeon card.
881 * The following lines read the dib section so it is put in inSync mode
882 * before glDrawPixels is called and the crash is prevented. There won't
883 * be any interfering gdi accesses, because UnlockRect is called from
884 * ReleaseDC, and the app won't use the dc any more afterwards.
886 if(This->Flags & SFLAG_DIBSECTION) {
888 read = This->resource.allocatedMemory[0];
891 switch (This->resource.format) {
892 /* No special care needed */
893 case WINED3DFMT_A4R4G4B4:
894 case WINED3DFMT_R5G6B5:
895 case WINED3DFMT_A1R5G5B5:
896 case WINED3DFMT_R8G8B8:
897 type = This->glDescription.glType;
898 fmt = This->glDescription.glFormat;
899 mem = This->resource.allocatedMemory;
902 case WINED3DFMT_X4R4G4B4:
905 unsigned short *data;
906 data = (unsigned short *)This->resource.allocatedMemory;
907 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
913 type = This->glDescription.glType;
914 fmt = This->glDescription.glFormat;
915 mem = This->resource.allocatedMemory;
919 case WINED3DFMT_X1R5G5B5:
922 unsigned short *data;
923 data = (unsigned short *)This->resource.allocatedMemory;
924 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
930 type = This->glDescription.glType;
931 fmt = This->glDescription.glFormat;
932 mem = This->resource.allocatedMemory;
936 case WINED3DFMT_X8R8G8B8:
938 /* make sure the X byte is set to alpha on, since it
939 could be any random value. This fixes the intro movie in Pirates! */
942 data = (unsigned int *)This->resource.allocatedMemory;
943 size = (This->lockedRect.bottom - This->lockedRect.top) * (This->lockedRect.right - This->lockedRect.left);
952 case WINED3DFMT_A8R8G8B8:
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;
963 case WINED3DFMT_A2R10G10B10:
965 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
966 vcheckGLcall("glPixelStorei");
968 type = This->glDescription.glType;
969 fmt = This->glDescription.glFormat;
970 mem = This->resource.allocatedMemory;
976 UINT pitch = IWineD3DSurface_GetPitch((IWineD3DSurface *) This); /* target is argb, 4 byte */
977 int height = This->glRect.bottom - This->glRect.top;
978 type = GL_UNSIGNED_BYTE;
981 mem = HeapAlloc(GetProcessHeap(), 0, This->resource.size * sizeof(DWORD));
983 ERR("Out of memory\n");
986 d3dfmt_convert_surface(This->resource.allocatedMemory,
998 FIXME("Unsupported Format %u in locking func\n", This->resource.format);
1001 type = This->glDescription.glType;
1002 fmt = This->glDescription.glFormat;
1003 mem = This->resource.allocatedMemory;
1006 glDrawPixels(This->lockedRect.right - This->lockedRect.left,
1007 (This->lockedRect.bottom - This->lockedRect.top)-1,
1010 checkGLcall("glDrawPixels");
1011 glPixelZoom(1.0,1.0);
1012 vcheckGLcall("glPixelZoom");
1014 glRasterPos3iv(&prev_rasterpos[0]);
1015 vcheckGLcall("glRasterPos3iv");
1017 /* Reset to previous pack row length */
1018 glPixelStorei(GL_UNPACK_ROW_LENGTH, skipBytes);
1019 vcheckGLcall("glPixelStorei GL_UNPACK_ROW_LENGTH");
1021 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
1022 vcheckGLcall("glPixelStorei GL_PACK_SWAP_BYTES");
1025 if(mem != This->resource.allocatedMemory) HeapFree(GetProcessHeap(), 0, mem);
1029 static void flush_to_framebuffer_texture(IWineD3DSurface *iface) {
1030 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1031 float glTexCoord[4];
1033 glTexCoord[0] = 0.0; /* left */
1034 glTexCoord[1] = (float) This->currentDesc.Width / (float) This->pow2Width; /* right */
1035 glTexCoord[2] = 0.0; /* top */
1036 glTexCoord[3] = (float) This->currentDesc.Height / (float) This->pow2Height; /* bottom */
1038 IWineD3DSurface_PreLoad(iface);
1042 /* Disable some fancy graphics effects */
1043 glDisable(GL_LIGHTING);
1044 checkGLcall("glDisable GL_LIGHTING");
1045 glDisable(GL_DEPTH_TEST);
1046 checkGLcall("glDisable GL_DEPTH_TEST");
1048 checkGLcall("glDisable GL_FOG");
1049 glDisable(GL_CULL_FACE);
1050 checkGLcall("glDisable GL_CULL_FACE");
1051 glDisable(GL_BLEND);
1052 checkGLcall("glDisable GL_BLEND");
1053 glDisable(GL_STENCIL_TEST);
1054 checkGLcall("glDisable GL_STENCIL_TEST");
1056 glEnable(GL_TEXTURE_2D);
1057 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
1058 checkGLcall("glEnable glBindTexture");
1060 /* No filtering for blts */
1061 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1062 checkGLcall("glTexParameteri");
1063 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1064 checkGLcall("glTexParameteri");
1066 /* Start drawing a quad */
1069 glColor3d(1.0f, 1.0f, 1.0f);
1070 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
1071 glVertex3f(0, 0, 0.0);
1073 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
1074 glVertex3f(0, This->currentDesc.Height, 0.0);
1076 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
1077 glVertex3d(This->currentDesc.Width, This->currentDesc.Height, 0.0);
1079 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
1080 glVertex3f(This->currentDesc.Width, 0, 0.0);
1083 checkGLcall("glEnd");
1085 /* Unbind the texture */
1086 glBindTexture(GL_TEXTURE_2D, 0);
1087 checkGLcall("glEnable glBindTexture");
1092 static HRESULT WINAPI IWineD3DSurfaceImpl_UnlockRect(IWineD3DSurface *iface) {
1093 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1094 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
1095 const char *buffername = "";
1096 IWineD3DSwapChainImpl *swapchain = NULL;
1097 BOOL backbuf = FALSE;
1099 if (!(This->Flags & SFLAG_LOCKED)) {
1100 WARN("trying to Unlock an unlocked surf@%p\n", This);
1101 return WINED3DERR_INVALIDCALL;
1104 if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) {
1105 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapchain);
1109 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
1110 if(iface == swapchain->backBuffer[i]) {
1118 buffername = "backBuffer";
1119 } else if ((swapchain != NULL) && iface == swapchain->frontBuffer) {
1120 buffername = "frontBuffer";
1121 } else if (iface == myDevice->depthStencilBuffer) {
1122 buffername = "depthStencilBuffer";
1123 } else if (iface == myDevice->render_targets[0]) {
1124 buffername = "renderTarget";
1128 if (swapchain != NULL) {
1129 IWineD3DSwapChain_Release((IWineD3DSwapChain *)swapchain);
1132 TRACE("(%p %s) : dirtyfied(%d)\n", This, buffername, This->Flags & SFLAG_DIRTY ? 1 : 0);
1134 if (!(This->Flags & SFLAG_DIRTY)) {
1135 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
1139 if (0 == This->resource.usage) { /* classic surface */
1140 IWineD3DBaseTextureImpl *impl;
1141 /* Check if the texture is bound, if yes dirtify the sampler to force a re-upload of the texture
1142 * Can't load the texture here because PreLoad may destroy and recreate the gl texture, so sampler
1143 * states need resetting
1145 if(IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&impl) == WINED3D_OK) {
1146 if(impl->baseTexture.bindCount) {
1147 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_SAMPLER(impl->baseTexture.sampler));
1149 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *) impl);
1151 } else if (WINED3DUSAGE_RENDERTARGET & This->resource.usage) { /* render surfaces */
1153 /****************************
1154 * TODO: Render targets are 'special' and
1155 * ?some? locking needs to be passed onto the context manager
1156 * so that it becomes possible to use auxiliary buffers, pbuffers
1157 * render-to-texture, shared, cached contexts etc...
1158 * ****************************/
1159 IWineD3DSwapChainImpl *implSwapChain;
1160 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
1162 if ((backbuf || iface == implSwapChain->frontBuffer || iface == myDevice->render_targets[0]) && wined3d_settings.rendertargetlock_mode != RTL_DISABLE) {
1167 /* glDrawPixels transforms the raster position as though it was a vertex -
1168 we want to draw at screen position 0,0 - Set up ortho (rhw) mode as
1169 per drawprim (and leave set - it will sort itself out due to last_was_rhw */
1170 myDevice->last_was_rhw = TRUE;
1171 /* Apply the projection and world matrices, it sets up orthogonal projection due to last_was_rhw */
1172 StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock, &myDevice->contexts[myDevice->activeContext]);
1173 StateTable[STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))].apply(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), myDevice->stateBlock, &myDevice->contexts[myDevice->activeContext]);
1174 /* Will reapply the projection matrix too */
1175 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL);
1177 if (iface == implSwapChain->frontBuffer) {
1178 glDrawBuffer(GL_FRONT);
1179 checkGLcall("glDrawBuffer GL_FRONT");
1180 } else if (backbuf || iface == myDevice->render_targets[0]) {
1181 glDrawBuffer(GL_BACK);
1182 checkGLcall("glDrawBuffer GL_BACK");
1185 /* Disable higher textures before calling glDrawPixels */
1186 for(tex = 1; tex < GL_LIMITS(samplers); tex++) {
1187 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1188 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + tex));
1189 checkGLcall("glActiveTextureARB");
1191 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(tex));
1192 glDisable(GL_TEXTURE_2D);
1193 checkGLcall("glDisable GL_TEXTURE_2D");
1194 glDisable(GL_TEXTURE_1D);
1195 checkGLcall("glDisable GL_TEXTURE_1D");
1197 /* Activate texture 0, but don't disable it necessarily */
1198 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1199 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
1200 checkGLcall("glActiveTextureARB");
1202 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
1204 /* And back buffers are not blended. Disable the depth test,
1205 that helps performance */
1206 glDisable(GL_BLEND);
1207 glDisable(GL_DEPTH_TEST);
1210 switch(wined3d_settings.rendertargetlock_mode) {
1214 flush_to_framebuffer_drawpixels(This);
1219 flush_to_framebuffer_texture(iface);
1224 static BOOL warned = FALSE;
1226 ERR("The application tries to write to the render target, but render target locking is disabled\n");
1233 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
1234 glDrawBuffer(GL_BACK);
1235 vcheckGLcall("glDrawBuffer");
1237 if(myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_TRUE ||
1238 myDevice->stateBlock->renderState[WINED3DRS_ZENABLE] == WINED3DZB_USEW) glEnable(GL_DEPTH_TEST);
1239 if (myDevice->stateBlock->renderState[WINED3DRS_ALPHABLENDENABLE]) glEnable(GL_BLEND);
1240 if (myDevice->stateBlock->renderState[WINED3DRS_FOGENABLE]) glEnable(GL_FOG);
1244 /** restore clean dirty state */
1245 IWineD3DSurface_CleanDirtyRect(iface);
1247 } else if(wined3d_settings.rendertargetlock_mode != RTL_DISABLE) {
1248 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1250 IWineD3DSwapChain_Release((IWineD3DSwapChain *)implSwapChain);
1252 } else if (WINED3DUSAGE_DEPTHSTENCIL & This->resource.usage) { /* stencil surfaces */
1254 if (iface == myDevice->depthStencilBuffer) {
1255 FIXME("TODO stencil depth surface unlocking surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1257 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1261 FIXME("unsupported unlocking to surface surf@%p usage(%s)\n", This, debug_d3dusage(This->resource.usage));
1265 This->Flags &= ~SFLAG_LOCKED;
1266 memset(&This->lockedRect, 0, sizeof(RECT));
1270 HRESULT WINAPI IWineD3DSurfaceImpl_GetDC(IWineD3DSurface *iface, HDC *pHDC) {
1271 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1272 WINED3DLOCKED_RECT lock;
1279 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1281 TRACE("(%p)->(%p)\n",This,pHDC);
1283 if(This->Flags & SFLAG_USERPTR) {
1284 ERR("Not supported on surfaces with an application-provided surfaces\n");
1288 /* Give more detailed info for ddraw */
1289 if (This->Flags & SFLAG_DCINUSE)
1290 return DDERR_DCALREADYCREATED;
1292 /* Can't GetDC if the surface is locked */
1293 if (This->Flags & SFLAG_LOCKED)
1294 return WINED3DERR_INVALIDCALL;
1296 memset(&lock, 0, sizeof(lock)); /* To be sure */
1298 /* Create a DIB section if there isn't a hdc yet */
1301 SYSTEM_INFO sysInfo;
1303 if(This->Flags & SFLAG_ACTIVELOCK) {
1304 ERR("Creating a DIB section while a lock is active. Uncertain consequences\n");
1307 switch (This->bytesPerPixel) {
1310 /* Allocate extra space to store the RGB bit masks. */
1311 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 3 * sizeof(DWORD));
1315 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER));
1319 /* Allocate extra space for a palette. */
1320 b_info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1321 sizeof(BITMAPINFOHEADER)
1323 * (1 << (This->bytesPerPixel * 8)));
1328 return E_OUTOFMEMORY;
1330 /* Some apps access the surface in via DWORDs, and do not take the necessary care at the end of the
1331 * surface. So we need at least extra 4 bytes at the end of the surface. Check against the page size,
1332 * if the last page used for the surface has at least 4 spare bytes we're safe, otherwise
1333 * add an extra line to the dib section
1335 GetSystemInfo(&sysInfo);
1336 if( ((This->resource.size + 3) % sysInfo.dwPageSize) < 4) {
1338 TRACE("Adding an extra line to the dib section\n");
1341 b_info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1342 if( (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
1343 b_info->bmiHeader.biWidth = This->currentDesc.Width;
1344 b_info->bmiHeader.biHeight = -This->currentDesc.Height -extraline;
1345 b_info->bmiHeader.biSizeImage = ( This->currentDesc.Height + extraline) * IWineD3DSurface_GetPitch(iface);
1346 /* Use the full pow2 image size(assigned below) because LockRect
1347 * will need it for a full glGetTexImage call
1350 b_info->bmiHeader.biWidth = This->pow2Width;
1351 b_info->bmiHeader.biHeight = -This->pow2Height -extraline;
1352 b_info->bmiHeader.biSizeImage = This->resource.size + extraline * IWineD3DSurface_GetPitch(iface);
1354 b_info->bmiHeader.biPlanes = 1;
1355 b_info->bmiHeader.biBitCount = This->bytesPerPixel * 8;
1357 b_info->bmiHeader.biXPelsPerMeter = 0;
1358 b_info->bmiHeader.biYPelsPerMeter = 0;
1359 b_info->bmiHeader.biClrUsed = 0;
1360 b_info->bmiHeader.biClrImportant = 0;
1362 /* Get the bit masks */
1363 masks = (DWORD *) &(b_info->bmiColors);
1364 switch (This->resource.format) {
1365 case WINED3DFMT_R8G8B8:
1366 usage = DIB_RGB_COLORS;
1367 b_info->bmiHeader.biCompression = BI_RGB;
1370 case WINED3DFMT_X1R5G5B5:
1371 case WINED3DFMT_A1R5G5B5:
1372 case WINED3DFMT_A4R4G4B4:
1373 case WINED3DFMT_X4R4G4B4:
1374 case WINED3DFMT_R3G3B2:
1375 case WINED3DFMT_A8R3G3B2:
1376 case WINED3DFMT_A2B10G10R10:
1377 case WINED3DFMT_A8B8G8R8:
1378 case WINED3DFMT_X8B8G8R8:
1379 case WINED3DFMT_A2R10G10B10:
1380 case WINED3DFMT_R5G6B5:
1381 case WINED3DFMT_A16B16G16R16:
1383 b_info->bmiHeader.biCompression = BI_BITFIELDS;
1384 masks[0] = formatEntry->redMask;
1385 masks[1] = formatEntry->greenMask;
1386 masks[2] = formatEntry->blueMask;
1390 /* Don't know palette */
1391 b_info->bmiHeader.biCompression = BI_RGB;
1398 HeapFree(GetProcessHeap(), 0, b_info);
1399 return HRESULT_FROM_WIN32(GetLastError());
1402 TRACE("Creating a DIB section with size %dx%dx%d, size=%d\n", b_info->bmiHeader.biWidth, b_info->bmiHeader.biHeight, b_info->bmiHeader.biBitCount, b_info->bmiHeader.biSizeImage);
1403 This->dib.DIBsection = CreateDIBSection(ddc, b_info, usage, &This->dib.bitmap_data, 0 /* Handle */, 0 /* Offset */);
1406 if (!This->dib.DIBsection) {
1407 ERR("CreateDIBSection failed!\n");
1408 HeapFree(GetProcessHeap(), 0, b_info);
1409 return HRESULT_FROM_WIN32(GetLastError());
1412 TRACE("DIBSection at : %p\n", This->dib.bitmap_data);
1414 /* copy the existing surface to the dib section */
1415 if(This->resource.allocatedMemory) {
1416 memcpy(This->dib.bitmap_data, This->resource.allocatedMemory, b_info->bmiHeader.biSizeImage);
1417 /* We won't need that any more */
1418 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1420 /* This is to make LockRect read the gl Texture although memory is allocated */
1421 This->Flags |= SFLAG_GLDIRTY;
1424 HeapFree(GetProcessHeap(), 0, b_info);
1426 /* Use the dib section from now on */
1427 This->resource.allocatedMemory = This->dib.bitmap_data;
1429 /* Now allocate a HDC */
1430 This->hDC = CreateCompatibleDC(0);
1431 This->dib.holdbitmap = SelectObject(This->hDC, This->dib.DIBsection);
1432 TRACE("using wined3d palette %p\n", This->palette);
1433 SelectPalette(This->hDC,
1434 This->palette ? This->palette->hpal : 0,
1437 This->Flags |= SFLAG_DIBSECTION;
1440 /* Lock the surface */
1441 hr = IWineD3DSurface_LockRect(iface,
1446 ERR("IWineD3DSurface_LockRect failed with hr = %08x\n", hr);
1447 /* keep the dib section */
1451 if(This->resource.format == WINED3DFMT_P8 ||
1452 This->resource.format == WINED3DFMT_A8P8) {
1455 PALETTEENTRY ent[256];
1457 GetPaletteEntries(This->palette->hpal, 0, 256, ent);
1458 for (n=0; n<256; n++) {
1459 col[n].rgbRed = ent[n].peRed;
1460 col[n].rgbGreen = ent[n].peGreen;
1461 col[n].rgbBlue = ent[n].peBlue;
1462 col[n].rgbReserved = 0;
1465 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1467 for (n=0; n<256; n++) {
1468 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
1469 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
1470 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
1471 col[n].rgbReserved = 0;
1475 SetDIBColorTable(This->hDC, 0, 256, col);
1479 TRACE("returning %p\n",*pHDC);
1480 This->Flags |= SFLAG_DCINUSE;
1485 HRESULT WINAPI IWineD3DSurfaceImpl_ReleaseDC(IWineD3DSurface *iface, HDC hDC) {
1486 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1488 TRACE("(%p)->(%p)\n",This,hDC);
1490 if (!(This->Flags & SFLAG_DCINUSE))
1491 return D3DERR_INVALIDCALL;
1493 /* we locked first, so unlock now */
1494 IWineD3DSurface_UnlockRect(iface);
1496 This->Flags &= ~SFLAG_DCINUSE;
1501 /* ******************************************************
1502 IWineD3DSurface Internal (No mapping to directx api) parts follow
1503 ****************************************************** */
1505 HRESULT d3dfmt_get_conv(IWineD3DSurfaceImpl *This, BOOL need_alpha_ck, BOOL use_texturing, GLenum *format, GLenum *internal, GLenum *type, CONVERT_TYPES *convert, int *target_bpp) {
1506 BOOL colorkey_active = need_alpha_ck && (This->CKeyFlags & DDSD_CKSRCBLT);
1507 const PixelFormatDesc *formatEntry = getFormatDescEntry(This->resource.format);
1509 /* Default values: From the surface */
1510 *format = formatEntry->glFormat;
1511 *internal = formatEntry->glInternal;
1512 *type = formatEntry->glType;
1513 *convert = NO_CONVERSION;
1514 *target_bpp = This->bytesPerPixel;
1516 /* Ok, now look if we have to do any conversion */
1517 switch(This->resource.format) {
1522 /* Use conversion when the paletted texture extension is not available, or when it is available make sure it is used
1523 * for texturing as it won't work for calls like glDraw-/glReadPixels and further also use conversion in case of color keying.
1525 if(!GL_SUPPORT(EXT_PALETTED_TEXTURE) || colorkey_active || (!use_texturing && GL_SUPPORT(EXT_PALETTED_TEXTURE)) ) {
1527 *internal = GL_RGBA;
1528 *type = GL_UNSIGNED_BYTE;
1530 if(colorkey_active) {
1531 *convert = CONVERT_PALETTED_CK;
1533 *convert = CONVERT_PALETTED;
1539 case WINED3DFMT_R3G3B2:
1540 /* **********************
1541 GL_UNSIGNED_BYTE_3_3_2
1542 ********************** */
1543 if (colorkey_active) {
1544 /* This texture format will never be used.. So do not care about color keying
1545 up until the point in time it will be needed :-) */
1546 FIXME(" ColorKeying not supported in the RGB 332 format !\n");
1550 case WINED3DFMT_R5G6B5:
1551 if (colorkey_active) {
1552 *convert = CONVERT_CK_565;
1554 *internal = GL_RGBA;
1555 *type = GL_UNSIGNED_SHORT_5_5_5_1;
1559 case WINED3DFMT_R8G8B8:
1560 if (colorkey_active) {
1561 *convert = CONVERT_CK_RGB24;
1563 *internal = GL_RGBA;
1564 *type = GL_UNSIGNED_INT_8_8_8_8;
1569 case WINED3DFMT_X8R8G8B8:
1570 if (colorkey_active) {
1571 *convert = CONVERT_RGB32_888;
1573 *internal = GL_RGBA;
1574 *type = GL_UNSIGNED_INT_8_8_8_8;
1585 HRESULT d3dfmt_convert_surface(BYTE *src, BYTE *dst, UINT pitch, UINT width, UINT height, UINT outpitch, CONVERT_TYPES convert, IWineD3DSurfaceImpl *surf) {
1586 BYTE *source, *dest;
1587 TRACE("(%p)->(%p),(%d,%d,%d,%d,%p)\n", src, dst, pitch, height, outpitch, convert, surf);
1592 memcpy(dst, src, pitch * height);
1595 case CONVERT_PALETTED:
1596 case CONVERT_PALETTED_CK:
1598 IWineD3DPaletteImpl* pal = surf->palette;
1604 /* TODO: If we are a sublevel, try to get the palette from level 0 */
1608 /* Still no palette? Use the device's palette */
1609 /* Get the surface's palette */
1610 for (i = 0; i < 256; i++) {
1611 IWineD3DDeviceImpl *device = surf->resource.wineD3DDevice;
1613 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1614 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1615 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1616 if ((convert == CONVERT_PALETTED_CK) &&
1617 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1618 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1619 /* We should maybe here put a more 'neutral' color than the standard bright purple
1620 one often used by application to prevent the nice purple borders when bi-linear
1628 TRACE("Using surface palette %p\n", pal);
1629 /* Get the surface's palette */
1630 for (i = 0; i < 256; i++) {
1631 table[i][0] = pal->palents[i].peRed;
1632 table[i][1] = pal->palents[i].peGreen;
1633 table[i][2] = pal->palents[i].peBlue;
1634 if ((convert == CONVERT_PALETTED_CK) &&
1635 (i >= surf->SrcBltCKey.dwColorSpaceLowValue) &&
1636 (i <= surf->SrcBltCKey.dwColorSpaceHighValue)) {
1637 /* We should maybe here put a more 'neutral' color than the standard bright purple
1638 one often used by application to prevent the nice purple borders when bi-linear
1647 for (y = 0; y < height; y++)
1649 source = src + pitch * y;
1650 dest = dst + outpitch * y;
1651 /* This is an 1 bpp format, using the width here is fine */
1652 for (x = 0; x < width; x++) {
1653 BYTE color = *source++;
1654 *dest++ = table[color][0];
1655 *dest++ = table[color][1];
1656 *dest++ = table[color][2];
1657 *dest++ = table[color][3];
1663 case CONVERT_CK_565:
1665 /* Converting the 565 format in 5551 packed to emulate color-keying.
1667 Note : in all these conversion, it would be best to average the averaging
1668 pixels to get the color of the pixel that will be color-keyed to
1669 prevent 'color bleeding'. This will be done later on if ever it is
1672 Note2: Nvidia documents say that their driver does not support alpha + color keying
1673 on the same surface and disables color keying in such a case
1679 TRACE("Color keyed 565\n");
1681 for (y = 0; y < height; y++) {
1682 Source = (WORD *) (src + y * pitch);
1683 Dest = (WORD *) (dst + y * outpitch);
1684 for (x = 0; x < width; x++ ) {
1685 WORD color = *Source++;
1686 *Dest = ((color & 0xFFC0) | ((color & 0x1F) << 1));
1687 if ((color < surf->SrcBltCKey.dwColorSpaceLowValue) ||
1688 (color > surf->SrcBltCKey.dwColorSpaceHighValue)) {
1698 ERR("Unsupported conversation type %d\n", convert);
1703 /* This function is used in case of 8bit paletted textures to upload the palette.
1704 For now it only supports GL_EXT_paletted_texture extension but support for other
1705 extensions like ARB_fragment_program and ATI_fragment_shaders will be added as well.
1707 void d3dfmt_p8_upload_palette(IWineD3DSurface *iface, CONVERT_TYPES convert) {
1708 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1709 IWineD3DPaletteImpl* pal = This->palette;
1714 /* Still no palette? Use the device's palette */
1715 /* Get the surface's palette */
1716 for (i = 0; i < 256; i++) {
1717 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
1719 table[i][0] = device->palettes[device->currentPalette][i].peRed;
1720 table[i][1] = device->palettes[device->currentPalette][i].peGreen;
1721 table[i][2] = device->palettes[device->currentPalette][i].peBlue;
1722 if ((convert == CONVERT_PALETTED_CK) &&
1723 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1724 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1725 /* We should maybe here put a more 'neutral' color than the standard bright purple
1726 one often used by application to prevent the nice purple borders when bi-linear
1734 TRACE("Using surface palette %p\n", pal);
1735 /* Get the surface's palette */
1736 for (i = 0; i < 256; i++) {
1737 table[i][0] = pal->palents[i].peRed;
1738 table[i][1] = pal->palents[i].peGreen;
1739 table[i][2] = pal->palents[i].peBlue;
1740 if ((convert == CONVERT_PALETTED_CK) &&
1741 (i >= This->SrcBltCKey.dwColorSpaceLowValue) &&
1742 (i <= This->SrcBltCKey.dwColorSpaceHighValue)) {
1743 /* We should maybe here put a more 'neutral' color than the standard bright purple
1744 one often used by application to prevent the nice purple borders when bi-linear
1752 GL_EXTCALL(glColorTableEXT(GL_TEXTURE_2D,GL_RGBA,256,GL_RGBA,GL_UNSIGNED_BYTE, table));
1755 static HRESULT WINAPI IWineD3DSurfaceImpl_LoadTexture(IWineD3DSurface *iface) {
1756 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1757 GLenum format, internal, type;
1758 CONVERT_TYPES convert;
1760 int width, pitch, outpitch;
1763 if (This->Flags & SFLAG_INTEXTURE) {
1764 TRACE("Surface already in texture\n");
1767 if (This->Flags & SFLAG_DIRTY) {
1768 TRACE("Reloading because surface is dirty\n");
1769 } else if(/* Reload: gl texture has ck, now no ckey is set OR */
1770 ((This->Flags & SFLAG_GLCKEY) && (!(This->CKeyFlags & DDSD_CKSRCBLT))) ||
1771 /* Reload: vice versa OR */
1772 ((!(This->Flags & SFLAG_GLCKEY)) && (This->CKeyFlags & DDSD_CKSRCBLT)) ||
1773 /* Also reload: Color key is active AND the color key has changed */
1774 ((This->CKeyFlags & DDSD_CKSRCBLT) && (
1775 (This->glCKey.dwColorSpaceLowValue != This->SrcBltCKey.dwColorSpaceLowValue) ||
1776 (This->glCKey.dwColorSpaceHighValue != This->SrcBltCKey.dwColorSpaceHighValue)))) {
1777 TRACE("Reloading because of color keying\n");
1779 TRACE("surface isn't dirty\n");
1783 This->Flags &= ~SFLAG_DIRTY;
1785 /* Resources are placed in system RAM and do not need to be recreated when a device is lost.
1786 * These resources are not bound by device size or format restrictions. Because of this,
1787 * these resources cannot be accessed by the Direct3D device nor set as textures or render targets.
1788 * However, these resources can always be created, locked, and copied.
1790 if (This->resource.pool == WINED3DPOOL_SCRATCH && !(This->Flags & SFLAG_FORCELOAD) )
1792 FIXME("(%p) Operation not supported for scratch textures\n",This);
1793 return WINED3DERR_INVALIDCALL;
1796 if (This->Flags & SFLAG_INPBUFFER) {
1797 if (This->glDescription.level != 0)
1798 FIXME("Surface in texture is only supported for level 0\n");
1799 else if (This->resource.format == WINED3DFMT_P8 || This->resource.format == WINED3DFMT_A8P8 ||
1800 This->resource.format == WINED3DFMT_DXT1 || This->resource.format == WINED3DFMT_DXT2 ||
1801 This->resource.format == WINED3DFMT_DXT3 || This->resource.format == WINED3DFMT_DXT4 ||
1802 This->resource.format == WINED3DFMT_DXT5)
1803 FIXME("Format %d not supported\n", This->resource.format);
1809 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1810 vcheckGLcall("glGetIntegerv");
1811 glReadBuffer(GL_BACK);
1812 vcheckGLcall("glReadBuffer");
1814 glCopyTexImage2D(This->glDescription.target,
1815 This->glDescription.level,
1816 This->glDescription.glFormatInternal,
1819 This->currentDesc.Width,
1820 This->currentDesc.Height,
1823 checkGLcall("glCopyTexImage2D");
1824 glReadBuffer(prevRead);
1825 vcheckGLcall("glReadBuffer");
1829 TRACE("Updating target %d\n", This->glDescription.target);
1830 This->Flags |= SFLAG_INTEXTURE;
1835 if(This->CKeyFlags & DDSD_CKSRCBLT) {
1836 This->Flags |= SFLAG_GLCKEY;
1837 This->glCKey = This->SrcBltCKey;
1839 else This->Flags &= ~SFLAG_GLCKEY;
1841 d3dfmt_get_conv(This, TRUE /* We need color keying */, TRUE /* We will use textures */, &format, &internal, &type, &convert, &bpp);
1843 /* The width is in 'length' not in bytes */
1844 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET)
1845 width = This->currentDesc.Width;
1847 width = This->pow2Width;
1849 pitch = IWineD3DSurface_GetPitch(iface);
1851 if((convert != NO_CONVERSION) && This->resource.allocatedMemory) {
1852 int height = This->glRect.bottom - This->glRect.top;
1854 /* Stick to the alignment for the converted surface too, makes it easier to load the surface */
1855 outpitch = width * bpp;
1856 outpitch = (outpitch + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
1858 mem = HeapAlloc(GetProcessHeap(), 0, outpitch * height);
1860 ERR("Out of memory %d, %d!\n", outpitch, height);
1861 return WINED3DERR_OUTOFVIDEOMEMORY;
1863 d3dfmt_convert_surface(This->resource.allocatedMemory, mem, pitch, width, height, outpitch, convert, This);
1865 This->Flags |= SFLAG_CONVERTED;
1866 } else if (This->resource.format == WINED3DFMT_P8 && GL_SUPPORT(EXT_PALETTED_TEXTURE)) {
1867 d3dfmt_p8_upload_palette(iface, convert);
1868 This->Flags &= ~SFLAG_CONVERTED;
1869 mem = This->resource.allocatedMemory;
1871 This->Flags &= ~SFLAG_CONVERTED;
1872 mem = This->resource.allocatedMemory;
1875 /* Make sure the correct pitch is used */
1876 glPixelStorei(GL_UNPACK_ROW_LENGTH, width);
1878 if (NP2_REPACK == wined3d_settings.nonpower2_mode && (This->Flags & SFLAG_NONPOW2) && !(This->Flags & SFLAG_OVERSIZE)) {
1879 TRACE("non power of two support\n");
1880 surface_allocate_surface(This, internal, This->pow2Width, This->pow2Height, format, type);
1882 surface_upload_data(This, This->pow2Width, This->pow2Height, format, type, mem);
1885 surface_allocate_surface(This, internal, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type);
1887 surface_upload_data(This, This->glRect.right - This->glRect.left, This->glRect.bottom - This->glRect.top, format, type, mem);
1891 /* Restore the default pitch */
1892 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
1894 if (mem != This->resource.allocatedMemory)
1895 HeapFree(GetProcessHeap(), 0, mem);
1899 static unsigned int gen = 0;
1902 if ((gen % 10) == 0) {
1903 snprintf(buffer, sizeof(buffer), "/tmp/surface%p_type%u_level%u_%u.ppm", This, This->glDescription.target, This->glDescription.level, gen);
1904 IWineD3DSurfaceImpl_SaveSnapshot(iface, buffer);
1907 * debugging crash code
1916 if (!(This->Flags & SFLAG_DONOTFREE)) {
1917 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
1918 This->resource.allocatedMemory = NULL;
1926 HRESULT WINAPI IWineD3DSurfaceImpl_SaveSnapshot(IWineD3DSurface *iface, const char* filename) {
1929 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
1930 char *allocatedMemory;
1932 IWineD3DSwapChain *swapChain = NULL;
1934 GLuint tmpTexture = 0;
1937 Textures my not be stored in ->allocatedgMemory and a GlTexture
1938 so we should lock the surface before saving a snapshot, or at least check that
1940 /* TODO: Compressed texture images can be obtained from the GL in uncompressed form
1941 by calling GetTexImage and in compressed form by calling
1942 GetCompressedTexImageARB. Queried compressed images can be saved and
1943 later reused by calling CompressedTexImage[123]DARB. Pre-compressed
1944 texture images do not need to be processed by the GL and should
1945 significantly improve texture loading performance relative to uncompressed
1948 /* Setup the width and height to be the internal texture width and height. */
1949 width = This->pow2Width;
1950 height = This->pow2Height;
1951 /* check to see if were a 'virtual' texture e.g. were not a pbuffer of texture were a back buffer*/
1952 IWineD3DSurface_GetContainer(iface, &IID_IWineD3DSwapChain, (void **)&swapChain);
1954 if (swapChain || (This->Flags & SFLAG_INPBUFFER)) { /* if were not a real texture then read the back buffer into a real texture*/
1955 /* we don't want to interfere with the back buffer so read the data into a temporary texture and then save the data out of the temporary texture */
1958 FIXME("(%p) This surface needs to be locked before a snapshot can be taken\n", This);
1959 glEnable(GL_TEXTURE_2D);
1961 glGenTextures(1, &tmpTexture);
1962 glBindTexture(GL_TEXTURE_2D, tmpTexture);
1964 glTexImage2D(GL_TEXTURE_2D,
1971 GL_UNSIGNED_INT_8_8_8_8_REV,
1974 glGetIntegerv(GL_READ_BUFFER, &prevRead);
1975 vcheckGLcall("glGetIntegerv");
1976 glReadBuffer(GL_BACK);
1977 vcheckGLcall("glReadBuffer");
1978 glCopyTexImage2D(GL_TEXTURE_2D,
1987 checkGLcall("glCopyTexImage2D");
1988 glReadBuffer(prevRead);
1991 } else { /* bind the real texture */
1992 IWineD3DSurface_PreLoad(iface);
1994 allocatedMemory = HeapAlloc(GetProcessHeap(), 0, width * height * 4);
1996 FIXME("Saving texture level %d width %d height %d\n", This->glDescription.level, width, height);
1997 glGetTexImage(GL_TEXTURE_2D,
1998 This->glDescription.level,
2000 GL_UNSIGNED_INT_8_8_8_8_REV,
2002 checkGLcall("glTexImage2D");
2004 glBindTexture(GL_TEXTURE_2D, 0);
2005 glDeleteTextures(1, &tmpTexture);
2009 f = fopen(filename, "w+");
2011 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
2012 return WINED3DERR_INVALIDCALL;
2014 /* Save the dat out to a TGA file because 1: it's an easy raw format, 2: it supports an alpha chanel*/
2015 TRACE("(%p) opened %s with format %s\n", This, filename, debug_d3dformat(This->resource.format));
2030 fwrite(&width,2,1,f);
2032 fwrite(&height,2,1,f);
2037 /* if the data is upside down if we've fetched it from a back buffer, so it needs flipping again to make it the correct way up*/
2039 textureRow = allocatedMemory + (width * (height - 1) *4);
2041 textureRow = allocatedMemory;
2042 for (y = 0 ; y < height; y++) {
2043 for (i = 0; i < width; i++) {
2044 color = *((DWORD*)textureRow);
2045 fputc((color >> 16) & 0xFF, f); /* B */
2046 fputc((color >> 8) & 0xFF, f); /* G */
2047 fputc((color >> 0) & 0xFF, f); /* R */
2048 fputc((color >> 24) & 0xFF, f); /* A */
2051 /* take two rows of the pointer to the texture memory */
2053 (textureRow-= width << 3);
2056 TRACE("Closing file\n");
2060 IWineD3DSwapChain_Release(swapChain);
2062 HeapFree(GetProcessHeap(), 0, allocatedMemory);
2066 HRESULT WINAPI IWineD3DSurfaceImpl_CleanDirtyRect(IWineD3DSurface *iface) {
2067 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2068 This->Flags &= ~SFLAG_DIRTY;
2069 This->dirtyRect.left = This->currentDesc.Width;
2070 This->dirtyRect.top = This->currentDesc.Height;
2071 This->dirtyRect.right = 0;
2072 This->dirtyRect.bottom = 0;
2073 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY ? 1 : 0, This->dirtyRect.left,
2074 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2079 * Slightly inefficient way to handle multiple dirty rects but it works :)
2081 extern HRESULT WINAPI IWineD3DSurfaceImpl_AddDirtyRect(IWineD3DSurface *iface, CONST RECT* pDirtyRect) {
2082 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2083 IWineD3DBaseTexture *baseTexture = NULL;
2084 This->Flags |= SFLAG_DIRTY;
2085 if (NULL != pDirtyRect) {
2086 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
2087 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
2088 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
2089 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);
2091 This->dirtyRect.left = 0;
2092 This->dirtyRect.top = 0;
2093 This->dirtyRect.right = This->currentDesc.Width;
2094 This->dirtyRect.bottom = This->currentDesc.Height;
2096 TRACE("(%p) : Dirty?%d, Rect:(%d,%d,%d,%d)\n", This, This->Flags & SFLAG_DIRTY, This->dirtyRect.left,
2097 This->dirtyRect.top, This->dirtyRect.right, This->dirtyRect.bottom);
2098 /* if the container is a basetexture then mark it dirty. */
2099 if (IWineD3DSurface_GetContainer(iface, &IID_IWineD3DBaseTexture, (void **)&baseTexture) == WINED3D_OK) {
2100 TRACE("Passing to conatiner\n");
2101 IWineD3DBaseTexture_SetDirty(baseTexture, TRUE);
2102 IWineD3DBaseTexture_Release(baseTexture);
2107 HRESULT WINAPI IWineD3DSurfaceImpl_SetContainer(IWineD3DSurface *iface, IWineD3DBase *container) {
2108 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2110 TRACE("This %p, container %p\n", This, container);
2112 /* We can't keep a reference to the container, since the container already keeps a reference to us. */
2114 TRACE("Setting container to %p from %p\n", container, This->container);
2115 This->container = container;
2120 HRESULT WINAPI IWineD3DSurfaceImpl_SetFormat(IWineD3DSurface *iface, WINED3DFORMAT format) {
2121 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2122 const PixelFormatDesc *formatEntry = getFormatDescEntry(format);
2124 if (This->resource.format != WINED3DFMT_UNKNOWN) {
2125 FIXME("(%p) : The foramt of the surface must be WINED3DFORMAT_UNKNOWN\n", This);
2126 return WINED3DERR_INVALIDCALL;
2129 TRACE("(%p) : Setting texture foramt to (%d,%s)\n", This, format, debug_d3dformat(format));
2130 if (format == WINED3DFMT_UNKNOWN) {
2131 This->resource.size = 0;
2132 } else if (format == WINED3DFMT_DXT1) {
2133 /* DXT1 is half byte per pixel */
2134 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4)) >> 1;
2136 } else if (format == WINED3DFMT_DXT2 || format == WINED3DFMT_DXT3 ||
2137 format == WINED3DFMT_DXT4 || format == WINED3DFMT_DXT5) {
2138 This->resource.size = ((max(This->pow2Width, 4) * formatEntry->bpp) * max(This->pow2Height, 4));
2140 This->resource.size = ((This->pow2Width * formatEntry->bpp) + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
2141 This->resource.size *= This->pow2Height;
2145 /* Setup some glformat defaults */
2146 This->glDescription.glFormat = formatEntry->glFormat;
2147 This->glDescription.glFormatInternal = formatEntry->glInternal;
2148 This->glDescription.glType = formatEntry->glType;
2150 if (format != WINED3DFMT_UNKNOWN) {
2151 This->bytesPerPixel = formatEntry->bpp;
2152 This->pow2Size = (This->pow2Width * This->bytesPerPixel) * This->pow2Height;
2154 This->bytesPerPixel = 0;
2158 This->Flags |= (WINED3DFMT_D16_LOCKABLE == format) ? SFLAG_LOCKABLE : 0;
2160 This->resource.format = format;
2162 TRACE("(%p) : Size %d, pow2Size %d, bytesPerPixel %d, glFormat %d, glFotmatInternal %d, glType %d\n", This, This->resource.size, This->pow2Size, This->bytesPerPixel, This->glDescription.glFormat, This->glDescription.glFormatInternal, This->glDescription.glType);
2167 HRESULT WINAPI IWineD3DSurfaceImpl_SetMem(IWineD3DSurface *iface, void *Mem) {
2168 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2170 /* Render targets depend on their hdc, and we can't create a hdc on a user pointer */
2171 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2172 ERR("Not supported on render targets\n");
2173 return WINED3DERR_INVALIDCALL;
2176 if(This->Flags & (SFLAG_LOCKED | SFLAG_DCINUSE)) {
2177 WARN("Surface is locked or the HDC is in use\n");
2178 return WINED3DERR_INVALIDCALL;
2181 if(Mem && Mem != This->resource.allocatedMemory) {
2183 /* Do I have to copy the old surface content? */
2184 if(This->Flags & SFLAG_DIBSECTION) {
2185 /* Release the DC. No need to hold the critical section for the update
2186 * Thread because this thread runs only on front buffers, but this method
2187 * fails for render targets in the check above.
2189 SelectObject(This->hDC, This->dib.holdbitmap);
2190 DeleteDC(This->hDC);
2191 /* Release the DIB section */
2192 DeleteObject(This->dib.DIBsection);
2193 This->dib.bitmap_data = NULL;
2194 This->resource.allocatedMemory = NULL;
2196 This->Flags &= ~SFLAG_DIBSECTION;
2197 } else if(!(This->Flags & SFLAG_USERPTR)) {
2198 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2200 This->resource.allocatedMemory = Mem;
2201 This->Flags |= SFLAG_USERPTR;
2202 } else if(This->Flags & SFLAG_USERPTR) {
2203 /* Lockrect and GetDC will re-create the dib section and allocated memory */
2204 This->resource.allocatedMemory = NULL;
2205 This->Flags &= ~SFLAG_USERPTR;
2210 /* TODO: replace this function with context management routines */
2211 HRESULT WINAPI IWineD3DSurfaceImpl_SetPBufferState(IWineD3DSurface *iface, BOOL inPBuffer, BOOL inTexture) {
2212 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2215 This->Flags |= SFLAG_INPBUFFER;
2217 This->Flags &= ~SFLAG_INPBUFFER;
2221 This->Flags |= SFLAG_INTEXTURE;
2223 This->Flags &= ~SFLAG_INTEXTURE;
2229 static HRESULT WINAPI IWineD3DSurfaceImpl_Flip(IWineD3DSurface *iface, IWineD3DSurface *override, DWORD Flags) {
2230 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2231 IWineD3DDevice *D3D = (IWineD3DDevice *) This->resource.wineD3DDevice;
2232 TRACE("(%p)->(%p,%x)\n", This, override, Flags);
2234 /* Flipping is only supported on RenderTargets */
2235 if( !(This->resource.usage & WINED3DUSAGE_RENDERTARGET) ) return DDERR_NOTFLIPPABLE;
2238 /* DDraw sets this for the X11 surfaces, so don't confuse the user
2239 * FIXME("(%p) Target override is not supported by now\n", This);
2240 * Additionally, it isn't really possible to support triple-buffering
2241 * properly on opengl at all
2245 /* Flipping a OpenGL surface -> Use WineD3DDevice::Present */
2246 return IWineD3DDevice_Present(D3D, NULL, NULL, 0, NULL);
2249 /* Not called from the VTable */
2250 static HRESULT IWineD3DSurfaceImpl_BltOverride(IWineD3DSurfaceImpl *This, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2252 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2253 IWineD3DSwapChainImpl *swapchain = NULL;
2254 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2257 TRACE("(%p)->(%p,%p,%p,%08x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2259 /* Get the swapchain. One of the surfaces has to be a primary surface */
2260 IWineD3DSurface_GetContainer( (IWineD3DSurface *) This, &IID_IWineD3DSwapChain, (void **)&swapchain);
2261 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2263 IWineD3DSurface_GetContainer( (IWineD3DSurface *) Src, &IID_IWineD3DSwapChain, (void **)&swapchain);
2264 if(swapchain) IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2265 else return WINED3DERR_INVALIDCALL;
2271 rect.x1 = DestRect->left;
2272 rect.y1 = DestRect->top;
2273 rect.x2 = DestRect->right;
2274 rect.y2 = DestRect->bottom;
2278 rect.x2 = This->currentDesc.Width;
2279 rect.y2 = This->currentDesc.Height;
2282 /* Half-life does a Blt from the back buffer to the front buffer,
2283 * Full surface size, no flags... Use present instead
2287 /* First, check if we can do a Flip */
2289 /* Check rects - IWineD3DDevice_Present doesn't handle them */
2291 if( (SrcRect->left == 0) && (SrcRect->top == 0) &&
2292 (SrcRect->right == Src->currentDesc.Width) && (SrcRect->bottom == Src->currentDesc.Height) ) {
2299 /* Check the Destination rect and the surface sizes */
2301 (rect.x1 == 0) && (rect.y1 == 0) &&
2302 (rect.x2 == This->currentDesc.Width) && (rect.y2 == This->currentDesc.Height) &&
2303 (This->currentDesc.Width == Src->currentDesc.Width) &&
2304 (This->currentDesc.Height == Src->currentDesc.Height)) {
2305 /* These flags are unimportant for the flag check, remove them */
2307 if((Flags & ~(DDBLT_DONOTWAIT | DDBLT_WAIT)) == 0) {
2308 if( swapchain->backBuffer && ((IWineD3DSurface *) This == swapchain->frontBuffer) && ((IWineD3DSurface *) Src == swapchain->backBuffer[0]) ) {
2310 D3DSWAPEFFECT orig_swap = swapchain->presentParms.SwapEffect;
2312 /* The idea behind this is that a glReadPixels and a glDrawPixels call
2313 * take very long, while a flip is fast.
2314 * This applies to Half-Life, which does such Blts every time it finished
2315 * a frame, and to Prince of Persia 3D, which uses this to draw at least the main
2316 * menu. This is also used by all apps when they do windowed rendering
2318 * The problem is that flipping is not really the same as copying. After a
2319 * Blt the front buffer is a copy of the back buffer, and the back buffer is
2320 * untouched. Therefore it's necessary to override the swap effect
2321 * and to set it back after the flip.
2324 swapchain->presentParms.SwapEffect = WINED3DSWAPEFFECT_COPY;
2326 TRACE("Full screen back buffer -> front buffer blt, performing a flip instead\n");
2327 IWineD3DDevice_Present((IWineD3DDevice *) This->resource.wineD3DDevice,
2328 NULL, NULL, 0, NULL);
2330 swapchain->presentParms.SwapEffect = orig_swap;
2337 /* Blt from texture to rendertarget? */
2338 if( ( ( (IWineD3DSurface *) This == swapchain->frontBuffer) ||
2339 ( swapchain->backBuffer && (IWineD3DSurface *) This == swapchain->backBuffer[0]) )
2341 ( ( (IWineD3DSurface *) Src != swapchain->frontBuffer) &&
2342 ( swapchain->backBuffer && (IWineD3DSurface *) Src != swapchain->backBuffer[0]) ) ) {
2343 float glTexCoord[4];
2345 DDCOLORKEY oldBltCKey = {0,0};
2346 GLint oldLight, oldFog, oldDepth, oldBlend, oldCull, oldAlpha;
2347 GLint oldStencil, oldNVRegisterCombiners = 0;
2350 RECT SourceRectangle;
2353 TRACE("Blt from surface %p to rendertarget %p\n", Src, This);
2356 SourceRectangle.left = SrcRect->left;
2357 SourceRectangle.right = SrcRect->right;
2358 SourceRectangle.top = SrcRect->top;
2359 SourceRectangle.bottom = SrcRect->bottom;
2361 SourceRectangle.left = 0;
2362 SourceRectangle.right = Src->currentDesc.Width;
2363 SourceRectangle.top = 0;
2364 SourceRectangle.bottom = Src->currentDesc.Height;
2367 if(!CalculateTexRect(Src, &SourceRectangle, glTexCoord)) {
2368 /* Fall back to software */
2369 WARN("(%p) Source texture area (%d,%d)-(%d,%d) is too big\n", Src,
2370 SourceRectangle.left, SourceRectangle.top,
2371 SourceRectangle.right, SourceRectangle.bottom);
2372 return WINED3DERR_INVALIDCALL;
2375 /* Color keying: Check if we have to do a color keyed blt,
2376 * and if not check if a color key is activated.
2378 oldCKey = Src->CKeyFlags;
2379 if(!(Flags & DDBLT_KEYSRC) &&
2380 Src->CKeyFlags & DDSD_CKSRCBLT) {
2381 /* Ok, the surface has a color key, but we shall not use it -
2382 * Deactivate it for now, LoadTexture will catch this
2384 Src->CKeyFlags &= ~DDSD_CKSRCBLT;
2388 if(Flags & DDBLT_KEYDEST) {
2389 oldBltCKey = This->SrcBltCKey;
2390 /* Temporary replace the source color key with the destination one. We do this because the color conversion code which
2391 * is in the end called from LoadTexture works with the source color. At the end of this function we restore the color key.
2393 This->SrcBltCKey = This->DestBltCKey;
2394 } else if (Flags & DDBLT_KEYSRC)
2395 oldBltCKey = This->SrcBltCKey;
2397 /* Now load the surface */
2398 IWineD3DSurface_PreLoad((IWineD3DSurface *) Src);
2402 /* Save all the old stuff until we have a proper opengl state manager */
2403 oldLight = glIsEnabled(GL_LIGHTING);
2404 oldFog = glIsEnabled(GL_FOG);
2405 oldDepth = glIsEnabled(GL_DEPTH_TEST);
2406 oldBlend = glIsEnabled(GL_BLEND);
2407 oldCull = glIsEnabled(GL_CULL_FACE);
2408 oldAlpha = glIsEnabled(GL_ALPHA_TEST);
2409 oldStencil = glIsEnabled(GL_STENCIL_TEST);
2411 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2412 oldNVRegisterCombiners = glIsEnabled(GL_REGISTER_COMBINERS_NV);
2415 glGetIntegerv(GL_ALPHA_TEST_FUNC, &alphafunc);
2416 checkGLcall("glGetFloatv GL_ALPHA_TEST_FUNC");
2417 glGetFloatv(GL_ALPHA_TEST_REF, &alpharef);
2418 checkGLcall("glGetFloatv GL_ALPHA_TEST_REF");
2420 glGetIntegerv(GL_DRAW_BUFFER, &oldDraw);
2421 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer) {
2422 TRACE("Drawing to front buffer\n");
2423 glDrawBuffer(GL_FRONT);
2424 checkGLcall("glDrawBuffer GL_FRONT");
2427 /* Unbind the old texture */
2428 glBindTexture(GL_TEXTURE_2D, 0);
2429 IWineD3DDeviceImpl_MarkStateDirty(This->resource.wineD3DDevice, STATE_SAMPLER(0));
2431 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2432 /* We use texture unit 0 for blts */
2433 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
2434 checkGLcall("glActiveTextureARB");
2436 WARN("Multi-texturing is unsupported in the local OpenGL implementation\n");
2439 /* Disable some fancy graphics effects */
2440 glDisable(GL_LIGHTING);
2441 checkGLcall("glDisable GL_LIGHTING");
2442 glDisable(GL_DEPTH_TEST);
2443 checkGLcall("glDisable GL_DEPTH_TEST");
2445 checkGLcall("glDisable GL_FOG");
2446 glDisable(GL_BLEND);
2447 checkGLcall("glDisable GL_BLEND");
2448 glDisable(GL_CULL_FACE);
2449 checkGLcall("glDisable GL_CULL_FACE");
2450 glDisable(GL_STENCIL_TEST);
2451 checkGLcall("glDisable GL_STENCIL_TEST");
2452 if (GL_SUPPORT(NV_REGISTER_COMBINERS)) {
2453 glDisable(GL_REGISTER_COMBINERS_NV);
2454 checkGLcall("glDisable GL_REGISTER_COMBINERS_NV");
2457 /* Ok, we need 2d textures, but not 1D or 3D */
2458 glDisable(GL_TEXTURE_1D);
2459 checkGLcall("glDisable GL_TEXTURE_1D");
2460 glEnable(GL_TEXTURE_2D);
2461 checkGLcall("glEnable GL_TEXTURE_2D");
2462 glDisable(GL_TEXTURE_3D);
2463 checkGLcall("glDisable GL_TEXTURE_3D");
2465 /* Bind the texture */
2466 glBindTexture(GL_TEXTURE_2D, Src->glDescription.textureName);
2467 checkGLcall("glBindTexture");
2469 glEnable(GL_SCISSOR_TEST);
2471 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2473 /* No filtering for blts */
2474 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
2476 checkGLcall("glTexParameteri");
2477 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
2479 checkGLcall("glTexParameteri");
2480 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
2481 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
2482 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
2483 checkGLcall("glTexEnvi");
2485 /* This is for color keying */
2486 if(Flags & DDBLT_KEYSRC) {
2487 glEnable(GL_ALPHA_TEST);
2488 checkGLcall("glEnable GL_ALPHA_TEST");
2489 glAlphaFunc(GL_NOTEQUAL, 0.0);
2490 checkGLcall("glAlphaFunc\n");
2492 glDisable(GL_ALPHA_TEST);
2493 checkGLcall("glDisable GL_ALPHA_TEST");
2496 /* Draw a textured quad
2498 myDevice->last_was_rhw = TRUE;
2499 /* Apply the projection matrix, it sets up orthogonal projection due to last_was_rhw */
2500 StateTable[STATE_TRANSFORM(WINED3DTS_PROJECTION)].apply(STATE_TRANSFORM(WINED3DTS_PROJECTION), myDevice->stateBlock, &myDevice->contexts[myDevice->activeContext]);
2501 StateTable[STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0))].apply(STATE_TRANSFORM(WINED3DTS_WORLDMATRIX(0)), myDevice->stateBlock, &myDevice->contexts[myDevice->activeContext]);
2502 /* That will reapply the projection matrix too */
2503 IWineD3DDeviceImpl_MarkStateDirty(myDevice, STATE_VDECL);
2507 glColor3d(1.0f, 1.0f, 1.0f);
2508 glTexCoord2f(glTexCoord[0], glTexCoord[2]);
2513 glTexCoord2f(glTexCoord[0], glTexCoord[3]);
2514 glVertex3f(rect.x1, rect.y2, 0.0);
2516 glTexCoord2f(glTexCoord[1], glTexCoord[3]);
2521 glTexCoord2f(glTexCoord[1], glTexCoord[2]);
2526 checkGLcall("glEnd");
2528 /* Unbind the texture */
2529 glBindTexture(GL_TEXTURE_2D, 0);
2530 checkGLcall("glEnable glBindTexture");
2532 /* Restore the old settings */
2534 glEnable(GL_LIGHTING);
2535 checkGLcall("glEnable GL_LIGHTING");
2539 checkGLcall("glEnable GL_FOG");
2542 glEnable(GL_DEPTH_TEST);
2543 checkGLcall("glEnable GL_DEPTH_TEST");
2547 checkGLcall("glEnable GL_BLEND");
2550 glEnable(GL_CULL_FACE);
2551 checkGLcall("glEnable GL_CULL_FACE");
2554 glEnable(GL_STENCIL_TEST);
2555 checkGLcall("glEnable GL_STENCIL_TEST");
2558 glDisable(GL_ALPHA_TEST);
2559 checkGLcall("glDisable GL_ALPHA_TEST");
2561 glEnable(GL_ALPHA_TEST);
2562 checkGLcall("glEnable GL_ALPHA_TEST");
2564 if (GL_SUPPORT(NV_REGISTER_COMBINERS) && oldNVRegisterCombiners) {
2565 glEnable(GL_REGISTER_COMBINERS_NV);
2566 checkGLcall("glEnable GL_REGISTER_COMBINERS_NV");
2569 glAlphaFunc(alphafunc, alpharef);
2570 checkGLcall("glAlphaFunc\n");
2572 if(This == (IWineD3DSurfaceImpl *) swapchain->frontBuffer && oldDraw == GL_BACK) {
2573 glDrawBuffer(oldDraw);
2576 /* Restore the color key flags */
2577 if(oldCKey != Src->CKeyFlags) {
2578 Src->CKeyFlags = oldCKey;
2581 /* Restore the old color key */
2582 if (Flags & (DDBLT_KEYSRC | DDBLT_KEYDEST))
2583 This->SrcBltCKey = oldBltCKey;
2587 /* TODO: If the surface is locked often, perform the Blt in software on the memory instead */
2588 This->Flags |= SFLAG_GLDIRTY;
2594 /* Blt from rendertarget to texture? */
2595 if( (SrcSurface == swapchain->frontBuffer) ||
2596 (swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) ) {
2597 if( ( (IWineD3DSurface *) This != swapchain->frontBuffer) &&
2598 ( swapchain->backBuffer && (IWineD3DSurface *) This != swapchain->backBuffer[0]) ) {
2603 TRACE("Blt from rendertarget to texture\n");
2605 /* Call preload for the surface to make sure it isn't dirty */
2606 IWineD3DSurface_PreLoad((IWineD3DSurface *) This);
2609 srect.x1 = SrcRect->left;
2610 srect.y1 = SrcRect->top;
2611 srect.x2 = SrcRect->right;
2612 srect.y2 = SrcRect->bottom;
2616 srect.x2 = Src->currentDesc.Width;
2617 srect.y2 = Src->currentDesc.Height;
2622 /* Bind the target texture */
2623 glBindTexture(GL_TEXTURE_2D, This->glDescription.textureName);
2624 checkGLcall("glBindTexture");
2625 if(swapchain->backBuffer && SrcSurface == swapchain->backBuffer[0]) {
2626 glReadBuffer(GL_BACK);
2628 glReadBuffer(GL_FRONT);
2630 checkGLcall("glReadBuffer");
2632 xrel = (float) (srect.x2 - srect.x1) / (float) (rect.x2 - rect.x1);
2633 yrel = (float) (srect.y2 - srect.y1) / (float) (rect.y2 - rect.y1);
2635 /* I have to process this row by row to swap the image,
2636 * otherwise it would be upside down, so streching in y direction
2637 * doesn't cost extra time
2639 * However, streching in x direction can be avoided if not necessary
2641 for(row = rect.y1; row < rect.y2; row++) {
2642 if( (xrel - 1.0 < -eps) || (xrel - 1.0 > eps)) {
2643 /* Well, that stuff works, but it's very slow.
2644 * find a better way instead
2647 for(col = rect.x1; col < rect.x2; col++) {
2648 glCopyTexSubImage2D(GL_TEXTURE_2D,
2650 rect.x1 + col, This->currentDesc.Height - row - 1, /* xoffset, yoffset */
2651 srect.x1 + col * xrel, Src->currentDesc.Height - srect.y2 + row * yrel,
2655 glCopyTexSubImage2D(GL_TEXTURE_2D,
2657 rect.x1, rect.y2 + rect.y1 - row - 1, /* xoffset, yoffset */
2658 srect.x1, row - rect.y1,
2659 rect.x2-rect.x1, 1);
2663 vcheckGLcall("glCopyTexSubImage2D");
2666 if(!(This->Flags & SFLAG_DONOTFREE)) {
2667 HeapFree(GetProcessHeap(), 0, This->resource.allocatedMemory);
2668 This->resource.allocatedMemory = NULL;
2670 This->Flags |= SFLAG_GLDIRTY;
2678 if (Flags & DDBLT_COLORFILL) {
2679 /* This is easy to handle for the D3D Device... */
2681 IWineD3DSwapChainImpl *implSwapChain;
2683 TRACE("Colorfill\n");
2685 /* The color as given in the Blt function is in the format of the frame-buffer...
2686 * 'clear' expect it in ARGB format => we need to do some conversion :-)
2688 if (This->resource.format == WINED3DFMT_P8) {
2689 if (This->palette) {
2690 color = ((0xFF000000) |
2691 (This->palette->palents[DDBltFx->u5.dwFillColor].peRed << 16) |
2692 (This->palette->palents[DDBltFx->u5.dwFillColor].peGreen << 8) |
2693 (This->palette->palents[DDBltFx->u5.dwFillColor].peBlue));
2698 else if (This->resource.format == WINED3DFMT_R5G6B5) {
2699 if (DDBltFx->u5.dwFillColor == 0xFFFF) {
2702 color = ((0xFF000000) |
2703 ((DDBltFx->u5.dwFillColor & 0xF800) << 8) |
2704 ((DDBltFx->u5.dwFillColor & 0x07E0) << 5) |
2705 ((DDBltFx->u5.dwFillColor & 0x001F) << 3));
2708 else if ((This->resource.format == WINED3DFMT_R8G8B8) ||
2709 (This->resource.format == WINED3DFMT_X8R8G8B8) ) {
2710 color = 0xFF000000 | DDBltFx->u5.dwFillColor;
2712 else if (This->resource.format == WINED3DFMT_A8R8G8B8) {
2713 color = DDBltFx->u5.dwFillColor;
2716 ERR("Wrong surface type for BLT override(Format doesn't match) !\n");
2717 return WINED3DERR_INVALIDCALL;
2720 TRACE("Calling GetSwapChain with mydevice = %p\n", myDevice);
2721 IWineD3DDevice_GetSwapChain((IWineD3DDevice *)myDevice, 0, (IWineD3DSwapChain **)&implSwapChain);
2722 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) implSwapChain );
2723 if(implSwapChain->backBuffer && This == (IWineD3DSurfaceImpl*) implSwapChain->backBuffer[0]) {
2724 glDrawBuffer(GL_BACK);
2725 checkGLcall("glDrawBuffer(GL_BACK)");
2727 else if (This == (IWineD3DSurfaceImpl*) implSwapChain->frontBuffer) {
2728 glDrawBuffer(GL_FRONT);
2729 checkGLcall("glDrawBuffer(GL_FRONT)");
2732 ERR("Wrong surface type for BLT override(not on swapchain) !\n");
2733 return WINED3DERR_INVALIDCALL;
2736 TRACE("(%p) executing Render Target override, color = %x\n", This, color);
2738 IWineD3DDevice_Clear( (IWineD3DDevice *) myDevice,
2739 1 /* Number of rectangles */,
2741 WINED3DCLEAR_TARGET,
2746 /* Restore the original draw buffer */
2747 if(implSwapChain->backBuffer && implSwapChain->backBuffer[0]) {
2748 glDrawBuffer(GL_BACK);
2749 vcheckGLcall("glDrawBuffer");
2755 /* Default: Fall back to the generic blt */
2756 return WINED3DERR_INVALIDCALL;
2759 static HRESULT WINAPI IWineD3DSurfaceImpl_Blt(IWineD3DSurface *iface, RECT *DestRect, IWineD3DSurface *SrcSurface, RECT *SrcRect, DWORD Flags, DDBLTFX *DDBltFx) {
2760 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2761 IWineD3DSurfaceImpl *Src = (IWineD3DSurfaceImpl *) SrcSurface;
2762 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2763 TRACE("(%p)->(%p,%p,%p,%x,%p)\n", This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2764 TRACE("(%p): Usage is %s\n", This, debug_d3dusage(This->resource.usage));
2766 /* Accessing the depth stencil is supposed to fail between a BeginScene and EndScene pair */
2767 if(myDevice->inScene &&
2768 (iface == myDevice->stencilBufferTarget ||
2769 (SrcSurface && SrcSurface == myDevice->stencilBufferTarget))) {
2770 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2771 return WINED3DERR_INVALIDCALL;
2774 /* Special cases for RenderTargets */
2775 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2776 ( Src && (Src->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2777 if(IWineD3DSurfaceImpl_BltOverride(This, DestRect, SrcSurface, SrcRect, Flags, DDBltFx) == WINED3D_OK) return WINED3D_OK;
2780 /* For the rest call the X11 surface implementation.
2781 * For RenderTargets this should be implemented OpenGL accelerated in BltOverride,
2782 * other Blts are rather rare
2784 return IWineGDISurfaceImpl_Blt(iface, DestRect, SrcSurface, SrcRect, Flags, DDBltFx);
2787 HRESULT WINAPI IWineD3DSurfaceImpl_GetBltStatus(IWineD3DSurface *iface, DWORD Flags) {
2788 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *)iface;
2789 TRACE("(%p)->(%x)\n", This, Flags);
2794 case DDGBS_ISBLTDONE:
2798 return DDERR_INVALIDPARAMS;
2802 HRESULT WINAPI IWineD3DSurfaceImpl_GetFlipStatus(IWineD3DSurface *iface, DWORD Flags) {
2803 /* XXX: DDERR_INVALIDSURFACETYPE */
2805 TRACE("(%p)->(%08x)\n",iface,Flags);
2808 case DDGFS_ISFLIPDONE:
2812 return DDERR_INVALIDPARAMS;
2816 HRESULT WINAPI IWineD3DSurfaceImpl_IsLost(IWineD3DSurface *iface) {
2817 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2818 TRACE("(%p)\n", This);
2820 return This->Flags & SFLAG_LOST ? DDERR_SURFACELOST : WINED3D_OK;
2823 HRESULT WINAPI IWineD3DSurfaceImpl_Restore(IWineD3DSurface *iface) {
2824 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2825 TRACE("(%p)\n", This);
2827 /* So far we don't lose anything :) */
2828 This->Flags &= ~SFLAG_LOST;
2832 HRESULT WINAPI IWineD3DSurfaceImpl_BltFast(IWineD3DSurface *iface, DWORD dstx, DWORD dsty, IWineD3DSurface *Source, RECT *rsrc, DWORD trans) {
2833 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2834 IWineD3DSurfaceImpl *srcImpl = (IWineD3DSurfaceImpl *) Source;
2835 IWineD3DDeviceImpl *myDevice = This->resource.wineD3DDevice;
2836 TRACE("(%p)->(%d, %d, %p, %p, %08x\n", iface, dstx, dsty, Source, rsrc, trans);
2838 if(myDevice->inScene &&
2839 (iface == myDevice->stencilBufferTarget ||
2840 (Source && Source == myDevice->stencilBufferTarget))) {
2841 TRACE("Attempt to access the depth stencil surface in a BeginScene / EndScene pair, returning WINED3DERR_INVALIDCALL\n");
2842 return WINED3DERR_INVALIDCALL;
2845 /* Special cases for RenderTargets */
2846 if( (This->resource.usage & WINED3DUSAGE_RENDERTARGET) ||
2847 ( srcImpl && (srcImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) )) {
2849 RECT SrcRect, DstRect;
2853 SrcRect.left = rsrc->left;
2854 SrcRect.top= rsrc->top;
2855 SrcRect.bottom = rsrc->bottom;
2856 SrcRect.right = rsrc->right;
2860 SrcRect.right = srcImpl->currentDesc.Width;
2861 SrcRect.bottom = srcImpl->currentDesc.Height;
2864 DstRect.left = dstx;
2866 DstRect.right = dstx + SrcRect.right - SrcRect.left;
2867 DstRect.bottom = dsty + SrcRect.bottom - SrcRect.top;
2869 /* Convert BltFast flags into Btl ones because it is called from SurfaceImpl_Blt as well */
2870 if(trans & DDBLTFAST_SRCCOLORKEY)
2871 Flags |= DDBLT_KEYSRC;
2872 if(trans & DDBLTFAST_DESTCOLORKEY)
2873 Flags |= DDBLT_KEYDEST;
2874 if(trans & DDBLTFAST_WAIT)
2875 Flags |= DDBLT_WAIT;
2876 if(trans & DDBLTFAST_DONOTWAIT)
2877 Flags |= DDBLT_DONOTWAIT;
2879 if(IWineD3DSurfaceImpl_BltOverride(This, &DstRect, Source, &SrcRect, Flags, NULL) == WINED3D_OK) return WINED3D_OK;
2883 return IWineGDISurfaceImpl_BltFast(iface, dstx, dsty, Source, rsrc, trans);
2886 HRESULT WINAPI IWineD3DSurfaceImpl_GetPalette(IWineD3DSurface *iface, IWineD3DPalette **Pal) {
2887 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2888 TRACE("(%p)->(%p)\n", This, Pal);
2890 *Pal = (IWineD3DPalette *) This->palette;
2894 HRESULT WINAPI IWineD3DSurfaceImpl_RealizePalette(IWineD3DSurface *iface) {
2895 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2897 IWineD3DPaletteImpl *pal = This->palette;
2899 TRACE("(%p)\n", This);
2901 if(This->resource.format == WINED3DFMT_P8 ||
2902 This->resource.format == WINED3DFMT_A8P8)
2904 TRACE("Dirtifying surface\n");
2905 This->Flags |= SFLAG_DIRTY;
2908 if(This->Flags & SFLAG_DIBSECTION) {
2909 TRACE("(%p): Updating the hdc's palette\n", This);
2910 for (n=0; n<256; n++) {
2912 col[n].rgbRed = pal->palents[n].peRed;
2913 col[n].rgbGreen = pal->palents[n].peGreen;
2914 col[n].rgbBlue = pal->palents[n].peBlue;
2916 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2917 /* Use the default device palette */
2918 col[n].rgbRed = device->palettes[device->currentPalette][n].peRed;
2919 col[n].rgbGreen = device->palettes[device->currentPalette][n].peGreen;
2920 col[n].rgbBlue = device->palettes[device->currentPalette][n].peBlue;
2922 col[n].rgbReserved = 0;
2924 SetDIBColorTable(This->hDC, 0, 256, col);
2930 HRESULT WINAPI IWineD3DSurfaceImpl_SetPalette(IWineD3DSurface *iface, IWineD3DPalette *Pal) {
2931 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2932 IWineD3DPaletteImpl *PalImpl = (IWineD3DPaletteImpl *) Pal;
2933 TRACE("(%p)->(%p)\n", This, Pal);
2935 if(This->palette != NULL)
2936 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET)
2937 This->palette->Flags &= ~DDPCAPS_PRIMARYSURFACE;
2939 if(PalImpl != NULL) {
2940 if(This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
2941 /* Set the device's main palette if the palette
2942 * wasn't a primary palette before
2944 if(!(PalImpl->Flags & DDPCAPS_PRIMARYSURFACE)) {
2945 IWineD3DDeviceImpl *device = This->resource.wineD3DDevice;
2948 for(i=0; i < 256; i++) {
2949 device->palettes[device->currentPalette][i] = PalImpl->palents[i];
2953 (PalImpl)->Flags |= DDPCAPS_PRIMARYSURFACE;
2956 This->palette = PalImpl;
2958 return IWineD3DSurface_RealizePalette(iface);
2961 HRESULT WINAPI IWineD3DSurfaceImpl_SetColorKey(IWineD3DSurface *iface, DWORD Flags, DDCOLORKEY *CKey) {
2962 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
2963 TRACE("(%p)->(%08x,%p)\n", This, Flags, CKey);
2965 if ((Flags & DDCKEY_COLORSPACE) != 0) {
2966 FIXME(" colorkey value not supported (%08x) !\n", Flags);
2967 return DDERR_INVALIDPARAMS;
2970 /* Dirtify the surface, but only if a key was changed */
2972 switch (Flags & ~DDCKEY_COLORSPACE) {
2973 case DDCKEY_DESTBLT:
2974 This->DestBltCKey = *CKey;
2975 This->CKeyFlags |= DDSD_CKDESTBLT;
2978 case DDCKEY_DESTOVERLAY:
2979 This->DestOverlayCKey = *CKey;
2980 This->CKeyFlags |= DDSD_CKDESTOVERLAY;
2983 case DDCKEY_SRCOVERLAY:
2984 This->SrcOverlayCKey = *CKey;
2985 This->CKeyFlags |= DDSD_CKSRCOVERLAY;
2989 This->SrcBltCKey = *CKey;
2990 This->CKeyFlags |= DDSD_CKSRCBLT;
2995 switch (Flags & ~DDCKEY_COLORSPACE) {
2996 case DDCKEY_DESTBLT:
2997 This->CKeyFlags &= ~DDSD_CKDESTBLT;
3000 case DDCKEY_DESTOVERLAY:
3001 This->CKeyFlags &= ~DDSD_CKDESTOVERLAY;
3004 case DDCKEY_SRCOVERLAY:
3005 This->CKeyFlags &= ~DDSD_CKSRCOVERLAY;
3009 This->CKeyFlags &= ~DDSD_CKSRCBLT;
3017 static HRESULT WINAPI IWineD3DSurfaceImpl_PrivateSetup(IWineD3DSurface *iface) {
3018 /** Check against the maximum texture sizes supported by the video card **/
3019 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3021 TRACE("%p\n", This);
3022 if ((This->pow2Width > GL_LIMITS(texture_size) || This->pow2Height > GL_LIMITS(texture_size)) && !(This->resource.usage & (WINED3DUSAGE_RENDERTARGET | WINED3DUSAGE_DEPTHSTENCIL))) {
3023 /* one of three options
3024 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)
3025 2: Set the texture to the maxium size (bad idea)
3026 3: WARN and return WINED3DERR_NOTAVAILABLE;
3027 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.
3029 WARN("(%p) Creating an oversized surface\n", This);
3030 This->Flags |= SFLAG_OVERSIZE;
3032 /* This will be initialized on the first blt */
3033 This->glRect.left = 0;
3034 This->glRect.top = 0;
3035 This->glRect.right = 0;
3036 This->glRect.bottom = 0;
3038 /* No oversize, gl rect is the full texture size */
3039 This->Flags &= ~SFLAG_OVERSIZE;
3040 This->glRect.left = 0;
3041 This->glRect.top = 0;
3042 This->glRect.right = This->pow2Width;
3043 This->glRect.bottom = This->pow2Height;
3049 DWORD WINAPI IWineD3DSurfaceImpl_GetPitch(IWineD3DSurface *iface) {
3050 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3052 TRACE("(%p)\n", This);
3054 /* DXTn formats don't have exact pitches as they are to the new row of blocks,
3055 where each block is 4x4 pixels, 8 bytes (dxt1) and 16 bytes (dxt2/3/4/5)
3056 ie pitch = (width/4) * bytes per block */
3057 if (This->resource.format == WINED3DFMT_DXT1) /* DXT1 is 8 bytes per block */
3058 ret = ((This->currentDesc.Width + 3) >> 2) << 3;
3059 else if (This->resource.format == WINED3DFMT_DXT2 || This->resource.format == WINED3DFMT_DXT3 ||
3060 This->resource.format == WINED3DFMT_DXT4 || This->resource.format == WINED3DFMT_DXT5) /* DXT2/3/4/5 is 16 bytes per block */
3061 ret = ((This->currentDesc.Width + 3) >> 2) << 4;
3063 if (NP2_REPACK == wined3d_settings.nonpower2_mode || This->resource.usage & WINED3DUSAGE_RENDERTARGET) {
3064 /* Front and back buffers are always lockes/unlocked on currentDesc.Width */
3065 ret = This->bytesPerPixel * This->currentDesc.Width; /* Bytes / row */
3067 ret = This->bytesPerPixel * This->pow2Width;
3069 /* Surfaces are 32 bit aligned */
3070 ret = (ret + SURFACE_ALIGNMENT - 1) & ~(SURFACE_ALIGNMENT - 1);
3072 TRACE("(%p) Returning %d\n", This, ret);
3076 HRESULT WINAPI IWineD3DSurfaceImpl_SetOverlayPosition(IWineD3DSurface *iface, LONG X, LONG Y) {
3077 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3079 FIXME("(%p)->(%d,%d) Stub!\n", This, X, Y);
3081 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3083 TRACE("(%p): Not an overlay surface\n", This);
3084 return DDERR_NOTAOVERLAYSURFACE;
3090 HRESULT WINAPI IWineD3DSurfaceImpl_GetOverlayPosition(IWineD3DSurface *iface, LONG *X, LONG *Y) {
3091 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3093 FIXME("(%p)->(%p,%p) Stub!\n", This, X, Y);
3095 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3097 TRACE("(%p): Not an overlay surface\n", This);
3098 return DDERR_NOTAOVERLAYSURFACE;
3104 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlayZOrder(IWineD3DSurface *iface, DWORD Flags, IWineD3DSurface *Ref) {
3105 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3106 IWineD3DSurfaceImpl *RefImpl = (IWineD3DSurfaceImpl *) Ref;
3108 FIXME("(%p)->(%08x,%p) Stub!\n", This, Flags, RefImpl);
3110 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3112 TRACE("(%p): Not an overlay surface\n", This);
3113 return DDERR_NOTAOVERLAYSURFACE;
3119 HRESULT WINAPI IWineD3DSurfaceImpl_UpdateOverlay(IWineD3DSurface *iface, RECT *SrcRect, IWineD3DSurface *DstSurface, RECT *DstRect, DWORD Flags, WINEDDOVERLAYFX *FX) {
3120 IWineD3DSurfaceImpl *This = (IWineD3DSurfaceImpl *) iface;
3121 IWineD3DSurfaceImpl *Dst = (IWineD3DSurfaceImpl *) DstSurface;
3122 FIXME("(%p)->(%p, %p, %p, %08x, %p)\n", This, SrcRect, Dst, DstRect, Flags, FX);
3124 if(!(This->resource.usage & WINED3DUSAGE_OVERLAY))
3126 TRACE("(%p): Not an overlay surface\n", This);
3127 return DDERR_NOTAOVERLAYSURFACE;
3133 const IWineD3DSurfaceVtbl IWineD3DSurface_Vtbl =
3136 IWineD3DSurfaceImpl_QueryInterface,
3137 IWineD3DSurfaceImpl_AddRef,
3138 IWineD3DSurfaceImpl_Release,
3139 /* IWineD3DResource */
3140 IWineD3DSurfaceImpl_GetParent,
3141 IWineD3DSurfaceImpl_GetDevice,
3142 IWineD3DSurfaceImpl_SetPrivateData,
3143 IWineD3DSurfaceImpl_GetPrivateData,
3144 IWineD3DSurfaceImpl_FreePrivateData,
3145 IWineD3DSurfaceImpl_SetPriority,
3146 IWineD3DSurfaceImpl_GetPriority,
3147 IWineD3DSurfaceImpl_PreLoad,
3148 IWineD3DSurfaceImpl_GetType,
3149 /* IWineD3DSurface */
3150 IWineD3DSurfaceImpl_GetContainer,
3151 IWineD3DSurfaceImpl_GetDesc,
3152 IWineD3DSurfaceImpl_LockRect,
3153 IWineD3DSurfaceImpl_UnlockRect,
3154 IWineD3DSurfaceImpl_GetDC,
3155 IWineD3DSurfaceImpl_ReleaseDC,
3156 IWineD3DSurfaceImpl_Flip,
3157 IWineD3DSurfaceImpl_Blt,
3158 IWineD3DSurfaceImpl_GetBltStatus,
3159 IWineD3DSurfaceImpl_GetFlipStatus,
3160 IWineD3DSurfaceImpl_IsLost,
3161 IWineD3DSurfaceImpl_Restore,
3162 IWineD3DSurfaceImpl_BltFast,
3163 IWineD3DSurfaceImpl_GetPalette,
3164 IWineD3DSurfaceImpl_SetPalette,
3165 IWineD3DSurfaceImpl_RealizePalette,
3166 IWineD3DSurfaceImpl_SetColorKey,
3167 IWineD3DSurfaceImpl_GetPitch,
3168 IWineD3DSurfaceImpl_SetMem,
3169 IWineD3DSurfaceImpl_SetOverlayPosition,
3170 IWineD3DSurfaceImpl_GetOverlayPosition,
3171 IWineD3DSurfaceImpl_UpdateOverlayZOrder,
3172 IWineD3DSurfaceImpl_UpdateOverlay,
3174 IWineD3DSurfaceImpl_CleanDirtyRect,
3175 IWineD3DSurfaceImpl_AddDirtyRect,
3176 IWineD3DSurfaceImpl_LoadTexture,
3177 IWineD3DSurfaceImpl_SaveSnapshot,
3178 IWineD3DSurfaceImpl_SetContainer,
3179 IWineD3DSurfaceImpl_SetPBufferState,
3180 IWineD3DSurfaceImpl_SetGlTextureDesc,
3181 IWineD3DSurfaceImpl_GetGlDesc,
3182 IWineD3DSurfaceImpl_GetData,
3183 IWineD3DSurfaceImpl_SetFormat,
3184 IWineD3DSurfaceImpl_PrivateSetup