2 * IDirect3DSurface8 implementation
4 * Copyright 2002 Jason Edmeades
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/debug.h"
30 #include "d3d8_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(d3d_surface);
36 # define VTRACE(A) TRACE A
42 /* IDirect3DVolume IUnknown parts follow: */
43 HRESULT WINAPI IDirect3DSurface8Impl_QueryInterface(LPDIRECT3DSURFACE8 iface,REFIID riid,LPVOID *ppobj)
45 ICOM_THIS(IDirect3DSurface8Impl,iface);
47 if (IsEqualGUID(riid, &IID_IUnknown)
48 || IsEqualGUID(riid, &IID_IDirect3DSurface8)) {
49 IDirect3DSurface8Impl_AddRef(iface);
54 WARN("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppobj);
58 ULONG WINAPI IDirect3DSurface8Impl_AddRef(LPDIRECT3DSURFACE8 iface) {
59 ICOM_THIS(IDirect3DSurface8Impl,iface);
60 TRACE("(%p) : AddRef from %ld\n", This, This->ref);
64 ULONG WINAPI IDirect3DSurface8Impl_Release(LPDIRECT3DSURFACE8 iface) {
65 ICOM_THIS(IDirect3DSurface8Impl,iface);
66 ULONG ref = --This->ref;
67 TRACE("(%p) : ReleaseRef to %ld\n", This, This->ref);
69 HeapFree(GetProcessHeap(), 0, This->allocatedMemory);
70 HeapFree(GetProcessHeap(), 0, This);
75 /* IDirect3DSurface8: */
76 HRESULT WINAPI IDirect3DSurface8Impl_GetDevice(LPDIRECT3DSURFACE8 iface, IDirect3DDevice8** ppDevice) {
77 ICOM_THIS(IDirect3DSurface8Impl,iface);
78 TRACE("(%p) : returning %p\n", This, This->Device);
79 *ppDevice = (LPDIRECT3DDEVICE8) This->Device;
81 * Note Calling this method will increase the internal reference count
82 * on the IDirect3DDevice8 interface.
84 IDirect3DDevice8Impl_AddRef(*ppDevice);
87 HRESULT WINAPI IDirect3DSurface8Impl_SetPrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid, CONST void* pData, DWORD SizeOfData, DWORD Flags) {
88 ICOM_THIS(IDirect3DSurface8Impl,iface);
89 FIXME("(%p) : stub\n", This);
92 HRESULT WINAPI IDirect3DSurface8Impl_GetPrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid, void* pData, DWORD* pSizeOfData) {
93 ICOM_THIS(IDirect3DSurface8Impl,iface);
94 FIXME("(%p) : stub\n", This);
97 HRESULT WINAPI IDirect3DSurface8Impl_FreePrivateData(LPDIRECT3DSURFACE8 iface, REFGUID refguid) {
98 ICOM_THIS(IDirect3DSurface8Impl,iface);
99 FIXME("(%p) : stub\n", This);
102 HRESULT WINAPI IDirect3DSurface8Impl_GetContainer(LPDIRECT3DSURFACE8 iface, REFIID riid, void** ppContainer) {
103 ICOM_THIS(IDirect3DSurface8Impl,iface);
105 res = IUnknown_QueryInterface(This->Container, riid, ppContainer);
106 if (E_NOINTERFACE == res) {
108 * If the surface is created using CreateImageSurface, CreateRenderTarget,
109 * or CreateDepthStencilSurface, the surface is considered stand alone. In this case,
110 * GetContainer will return the Direct3D device used to create the surface.
112 res = IUnknown_QueryInterface(This->Container, &IID_IDirect3DDevice8, ppContainer);
114 TRACE("(%p) : returning %p\n", This, *ppContainer);
117 HRESULT WINAPI IDirect3DSurface8Impl_GetDesc(LPDIRECT3DSURFACE8 iface, D3DSURFACE_DESC *pDesc) {
118 ICOM_THIS(IDirect3DSurface8Impl,iface);
120 TRACE("(%p) : copying into %p\n", This, pDesc);
121 memcpy(pDesc, &This->myDesc, sizeof(D3DSURFACE_DESC));
124 HRESULT WINAPI IDirect3DSurface8Impl_LockRect(LPDIRECT3DSURFACE8 iface, D3DLOCKED_RECT* pLockedRect, CONST RECT* pRect, DWORD Flags) {
126 ICOM_THIS(IDirect3DSurface8Impl,iface);
128 /* fixme: should we really lock as such? */
130 if (FALSE == This->lockable) {
131 ERR("trying to lock unlockable surf@%p\n", This);
132 return D3DERR_INVALIDCALL;
135 if (This == This->Device->backBuffer || This == This->Device->renderTarget || This == This->Device->frontBuffer || This->Device->depthStencilBuffer) {
136 if (This == This->Device->backBuffer) {
137 TRACE("(%p, backBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
138 } else if (This == This->Device->frontBuffer) {
139 TRACE("(%p, frontBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
140 } else if (This == This->Device->renderTarget) {
141 TRACE("(%p, renderTarget) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
142 } else if (This == This->Device->depthStencilBuffer) {
143 TRACE("(%p, stencilBuffer) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
146 TRACE("(%p) : rect@%p flags(%08lx), output lockedRect@%p, memory@%p\n", This, pRect, Flags, pLockedRect, This->allocatedMemory);
149 pLockedRect->Pitch = This->bytesPerPixel * This->myDesc.Width; /* Bytes / row */
152 pLockedRect->pBits = This->allocatedMemory;
153 This->lockedRect.left = 0;
154 This->lockedRect.top = 0;
155 This->lockedRect.right = This->myDesc.Width;
156 This->lockedRect.bottom = This->myDesc.Height;
157 TRACE("Locked Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", &This->lockedRect, This->lockedRect.left, This->lockedRect.top, This->lockedRect.right, This->lockedRect.bottom);
159 TRACE("Lock Rect (%p) = l %ld, t %ld, r %ld, b %ld\n", pRect, pRect->left, pRect->top, pRect->right, pRect->bottom);
160 pLockedRect->pBits = This->allocatedMemory + (pLockedRect->Pitch * pRect->top) + (pRect->left * This->bytesPerPixel);
161 This->lockedRect.left = pRect->left;
162 This->lockedRect.top = pRect->top;
163 This->lockedRect.right = pRect->right;
164 This->lockedRect.bottom = pRect->bottom;
168 if (0 == This->myDesc.Usage) { /* classic surface */
170 /* Nothing to do ;) */
172 } else if (D3DUSAGE_RENDERTARGET & This->myDesc.Usage) { /* render surfaces */
174 if (This == This->Device->backBuffer || This == This->Device->renderTarget || This == This->Device->frontBuffer) {
181 * for render->surface copy begin to begin of allocatedMemory
182 * unlock can be more easy
184 pLockedRect->pBits = This->allocatedMemory;
187 vcheckGLcall("glFlush");
188 glGetIntegerv(GL_READ_BUFFER, &prev_read);
189 vcheckGLcall("glIntegerv");
190 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
191 vcheckGLcall("glIntegerv");
193 if (This == This->Device->backBuffer) {
194 glReadBuffer(GL_BACK);
195 } else if (This == This->Device->frontBuffer || This == This->Device->renderTarget) {
196 glReadBuffer(GL_FRONT);
197 } else if (This == This->Device->depthStencilBuffer) {
198 ERR("Stencil Buffer lock unsupported for now\n");
200 vcheckGLcall("glReadBuffer");
204 for (j = This->lockedRect.top; j < This->lockedRect.bottom - This->lockedRect.top; ++j) {
205 glReadPixels(This->lockedRect.left,
206 This->lockedRect.bottom - j - 1,
207 This->lockedRect.right - This->lockedRect.left,
209 D3DFmt2GLFmt(This->Device, This->myDesc.Format),
210 D3DFmt2GLType(This->Device, This->myDesc.Format),
211 (char *)pLockedRect->pBits + (pLockedRect->Pitch * (j-This->lockedRect.top)));
212 vcheckGLcall("glReadPixels");
216 glReadBuffer(prev_read);
217 vcheckGLcall("glReadBuffer");
220 FIXME("unsupported locking to Rendering surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
223 } else if (D3DUSAGE_DEPTHSTENCIL & This->myDesc.Usage) { /* stencil surfaces */
225 FIXME("TODO stencil depth surface locking surf@%p usage(%lu)\n", This, This->myDesc.Usage);
228 FIXME("unsupported locking to surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
231 if (Flags & (D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_READONLY)) {
236 * as seen in msdn docs
238 IDirect3DSurface8Impl_AddDirtyRect(iface, &This->lockedRect);
240 /** Dirtify Container if needed */
241 if (NULL != This->Container) {
242 IDirect3DBaseTexture8* cont = NULL;
243 hr = IUnknown_QueryInterface(This->Container, &IID_IDirect3DBaseTexture8, (void**) &cont);
245 if (SUCCEEDED(hr) && NULL != cont) {
246 IDirect3DBaseTexture8Impl_SetDirty(cont, TRUE);
247 IDirect3DBaseTexture8_Release(cont);
253 TRACE("returning memory@%p, pitch(%d) dirtyfied(%d)\n", pLockedRect->pBits, pLockedRect->Pitch, This->Dirty);
258 HRESULT WINAPI IDirect3DSurface8Impl_UnlockRect(LPDIRECT3DSURFACE8 iface) {
259 ICOM_THIS(IDirect3DSurface8Impl,iface);
261 if (FALSE == This->locked) {
262 ERR("trying to lock unlocked surf@%p\n", This);
263 return D3DERR_INVALIDCALL;
266 if (This == This->Device->backBuffer || This == This->Device->frontBuffer || This->Device->depthStencilBuffer) {
267 if (This == This->Device->backBuffer) {
268 TRACE("(%p, backBuffer) : dirtyfied(%d)\n", This, This->Dirty);
269 } else if (This == This->Device->frontBuffer) {
270 TRACE("(%p, frontBuffer) : dirtyfied(%d)\n", This, This->Dirty);
271 } else if (This == This->Device->depthStencilBuffer) {
272 TRACE("(%p, stencilBuffer) : dirtyfied(%d)\n", This, This->Dirty);
275 TRACE("(%p) : dirtyfied(%d)\n", This, This->Dirty);
277 /*TRACE("(%p) see if behavior is correct\n", This);*/
279 if (FALSE == This->Dirty) {
280 TRACE("(%p) : Not Dirtified so nothing to do, return now\n", This);
284 if (0 == This->myDesc.Usage) { /* classic surface */
287 * waiting to reload the surface via IDirect3DDevice8::UpdateTexture
289 } else if (D3DUSAGE_RENDERTARGET & This->myDesc.Usage) { /* render surfaces */
291 if (This == This->Device->backBuffer || This == This->Device->frontBuffer) {
294 GLint prev_rasterpos[4];
299 vcheckGLcall("glFlush");
300 glGetIntegerv(GL_DRAW_BUFFER, &prev_draw);
301 vcheckGLcall("glIntegerv");
302 glGetIntegerv(GL_PACK_SWAP_BYTES, &prev_store);
303 vcheckGLcall("glIntegerv");
304 glGetIntegerv(GL_CURRENT_RASTER_POSITION, &prev_rasterpos[0]);
305 vcheckGLcall("glIntegerv");
307 if (This == This->Device->backBuffer) {
308 glDrawBuffer(GL_BACK);
309 } else if (This == This->Device->frontBuffer) {
310 glDrawBuffer(GL_FRONT);
312 vcheckGLcall("glDrawBuffer");
314 glRasterPos2i(This->lockedRect.left, This->lockedRect.top);
315 vcheckGLcall("glRasterPos2f");
316 switch (This->myDesc.Format) {
319 glDrawPixels(This->lockedRect.right - This->lockedRect.left, This->lockedRect.bottom - This->lockedRect.top,
320 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, This->allocatedMemory);
321 vcheckGLcall("glDrawPixels");
326 glDrawPixels(This->lockedRect.right - This->lockedRect.left, This->lockedRect.bottom - This->lockedRect.top,
327 GL_RGB, GL_UNSIGNED_BYTE, This->allocatedMemory);
328 vcheckGLcall("glDrawPixels");
331 case D3DFMT_A8R8G8B8:
333 glPixelStorei(GL_PACK_SWAP_BYTES, TRUE);
334 vcheckGLcall("glPixelStorei");
335 glDrawPixels(This->lockedRect.right - This->lockedRect.left, This->lockedRect.bottom - This->lockedRect.top,
336 GL_BGRA, GL_UNSIGNED_BYTE, This->allocatedMemory);
337 vcheckGLcall("glDrawPixels");
338 glPixelStorei(GL_PACK_SWAP_BYTES, prev_store);
339 vcheckGLcall("glPixelStorei");
343 FIXME("Unsupported Format %u in locking func\n", This->myDesc.Format);
346 glDrawBuffer(prev_draw);
347 vcheckGLcall("glDrawBuffer");
348 glRasterPos3iv(&prev_rasterpos[0]);
349 vcheckGLcall("glRasterPos3iv");
352 /** restore clean dirty state */
353 IDirect3DSurface8Impl_CleanDirtyRect(iface);
356 FIXME("unsupported unlocking to Rendering surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
359 } else if (D3DUSAGE_DEPTHSTENCIL & This->myDesc.Usage) { /* stencil surfaces */
361 if (This == This->Device->depthStencilBuffer) {
362 FIXME("TODO stencil depth surface unlocking surf@%p usage(%lu)\n", This, This->myDesc.Usage);
364 FIXME("unsupported unlocking to StencilDepth surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
368 FIXME("unsupported unlocking to surface surf@%p usage(%lu)\n", This, This->myDesc.Usage);
372 This->locked = FALSE;
373 memset(&This->lockedRect, 0, sizeof(RECT));
377 ICOM_VTABLE(IDirect3DSurface8) Direct3DSurface8_Vtbl =
379 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
380 IDirect3DSurface8Impl_QueryInterface,
381 IDirect3DSurface8Impl_AddRef,
382 IDirect3DSurface8Impl_Release,
383 IDirect3DSurface8Impl_GetDevice,
384 IDirect3DSurface8Impl_SetPrivateData,
385 IDirect3DSurface8Impl_GetPrivateData,
386 IDirect3DSurface8Impl_FreePrivateData,
387 IDirect3DSurface8Impl_GetContainer,
388 IDirect3DSurface8Impl_GetDesc,
389 IDirect3DSurface8Impl_LockRect,
390 IDirect3DSurface8Impl_UnlockRect,
393 HRESULT WINAPI IDirect3DSurface8Impl_LoadTexture(LPDIRECT3DSURFACE8 iface, GLenum gl_target, GLenum gl_level) {
394 ICOM_THIS(IDirect3DSurface8Impl,iface);
396 if ((This->myDesc.Format == D3DFMT_P8 || This->myDesc.Format == D3DFMT_A8P8)
397 #if defined(GL_EXT_paletted_texture)
398 && !GL_SUPPORT_DEV(EXT_PALETTED_TEXTURE, This->Device)
402 * wanted a paletted texture and not really support it in HW
403 * so software emulation code begin
406 PALETTEENTRY* pal = This->Device->palettes[This->Device->currentPalette];
407 VOID* surface = (VOID*) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->myDesc.Width * This->myDesc.Height * sizeof(DWORD));
408 BYTE* dst = (BYTE*) surface;
409 BYTE* src = (BYTE*) This->allocatedMemory;
411 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
413 *dst++ = pal[color].peRed;
414 *dst++ = pal[color].peGreen;
415 *dst++ = pal[color].peBlue;
416 if (This->myDesc.Format == D3DFMT_A8P8)
417 *dst++ = pal[color].peFlags;
422 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
432 glTexImage2D(gl_target,
441 checkGLcall("glTexImage2D");
442 HeapFree(GetProcessHeap(), 0, surface);
447 if (This->myDesc.Format == D3DFMT_DXT1 ||
448 This->myDesc.Format == D3DFMT_DXT3 ||
449 This->myDesc.Format == D3DFMT_DXT5) {
450 #if defined(GL_EXT_texture_compression_s3tc)
451 if (GL_SUPPORT_DEV(EXT_TEXTURE_COMPRESSION_S3TC, This->Device)) {
452 TRACE("Calling glCompressedTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, sz=%d, Mem=%p\n",
455 D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
460 This->allocatedMemory);
461 glCompressedTexImage2DARB(gl_target,
463 D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
468 This->allocatedMemory);
469 checkGLcall("glCommpressedTexTexImage2D");
473 TRACE("Calling glTexImage2D %x i=%d, intfmt=%x, w=%d, h=%d,0=%d, glFmt=%x, glType=%x, Mem=%p\n",
476 D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
480 D3DFmt2GLFmt(This->Device, This->myDesc.Format),
481 D3DFmt2GLType(This->Device, This->myDesc.Format),
482 This->allocatedMemory);
483 glTexImage2D(gl_target,
485 D3DFmt2GLIntFmt(This->Device, This->myDesc.Format),
489 D3DFmt2GLFmt(This->Device, This->myDesc.Format),
490 D3DFmt2GLType(This->Device, This->myDesc.Format),
491 This->allocatedMemory);
492 checkGLcall("glTexImage2D");
496 static unsigned int gen = 0;
499 if ((gen % 10) == 0) {
500 snprintf(buffer, sizeof(buffer), "/tmp/surface%u_level%u_%u.ppm", gl_target, gl_level, gen);
501 IDirect3DSurface8Impl_SaveSnapshot((LPDIRECT3DSURFACE8) This, buffer);
511 HRESULT WINAPI IDirect3DSurface8Impl_SaveSnapshot(LPDIRECT3DSURFACE8 iface, const char* filename) {
514 ICOM_THIS(IDirect3DSurface8Impl,iface);
516 f = fopen(filename, "w+");
518 ERR("opening of %s failed with: %s\n", filename, strerror(errno));
519 return D3DERR_INVALIDCALL;
522 TRACE("opened %s with format %s\n", filename, debug_d3dformat(This->myDesc.Format));
524 fprintf(f, "P6\n%u %u\n255\n", This->myDesc.Width, This->myDesc.Height);
525 switch (This->myDesc.Format) {
526 case D3DFMT_X8R8G8B8:
527 case D3DFMT_A8R8G8B8:
530 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
531 color = ((DWORD*) This->allocatedMemory)[i];
532 fputc((color >> 16) & 0xFF, f);
533 fputc((color >> 8) & 0xFF, f);
534 fputc((color >> 0) & 0xFF, f);
541 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
542 color = ((BYTE*) This->allocatedMemory) + (3 * i);
543 fputc((color[0]) & 0xFF, f);
544 fputc((color[1]) & 0xFF, f);
545 fputc((color[2]) & 0xFF, f);
549 case D3DFMT_A1R5G5B5:
552 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
553 color = ((WORD*) This->allocatedMemory)[i];
554 fputc(((color >> 10) & 0x1F) * 255 / 31, f);
555 fputc(((color >> 5) & 0x1F) * 255 / 31, f);
556 fputc(((color >> 0) & 0x1F) * 255 / 31, f);
560 case D3DFMT_A4R4G4B4:
563 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
564 color = ((WORD*) This->allocatedMemory)[i];
565 fputc(((color >> 8) & 0x0F) * 255 / 15, f);
566 fputc(((color >> 4) & 0x0F) * 255 / 15, f);
567 fputc(((color >> 0) & 0x0F) * 255 / 15, f);
575 for (i = 0; i < This->myDesc.Width * This->myDesc.Height; i++) {
576 color = ((WORD*) This->allocatedMemory)[i];
577 fputc(((color >> 11) & 0x1F) * 255 / 31, f);
578 fputc(((color >> 5) & 0x3F) * 255 / 63, f);
579 fputc(((color >> 0) & 0x1F) * 255 / 31, f);
584 FIXME("Unimplemented dump mode format(%u,%s)\n", This->myDesc.Format, debug_d3dformat(This->myDesc.Format));
590 HRESULT WINAPI IDirect3DSurface8Impl_CleanDirtyRect(LPDIRECT3DSURFACE8 iface) {
591 ICOM_THIS(IDirect3DSurface8Impl,iface);
593 This->dirtyRect.left = This->myDesc.Width;
594 This->dirtyRect.top = This->myDesc.Height;
595 This->dirtyRect.right = 0;
596 This->dirtyRect.bottom = 0;
602 * very stupid way to handle multiple dirty rects but it works :)
604 extern HRESULT WINAPI IDirect3DSurface8Impl_AddDirtyRect(LPDIRECT3DSURFACE8 iface, CONST RECT* pDirtyRect) {
605 ICOM_THIS(IDirect3DSurface8Impl,iface);
607 This->dirtyRect.left = min(This->dirtyRect.left, pDirtyRect->left);
608 This->dirtyRect.top = min(This->dirtyRect.top, pDirtyRect->top);
609 This->dirtyRect.right = max(This->dirtyRect.right, pDirtyRect->right);
610 This->dirtyRect.bottom = max(This->dirtyRect.bottom, pDirtyRect->bottom);