source: OGRE/trunk/ogrenew/RenderSystems/Direct3D9/src/OgreD3D9HardwarePixelBuffer.cpp @ 692

Revision 692, 16.8 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include "OgreD3D9HardwarePixelBuffer.h"
26#include "OgreD3D9Texture.h"
27#include "OgreD3D9Mappings.h"
28#include "OgreException.h"
29#include "OgreLogManager.h"
30#include "OgreStringConverter.h"
31#include "OgreBitwise.h"
32
33#include "OgreRoot.h"
34#include "OgreRenderSystem.h"
35
36#include "OgreNoMemoryMacros.h"
37#include <d3dx9.h>
38#include <dxerr9.h>
39#include "OgreMemoryMacros.h"
40
41namespace Ogre {
42
43//----------------------------------------------------------------------------- 
44
45D3D9HardwarePixelBuffer::D3D9HardwarePixelBuffer(HardwareBuffer::Usage usage):
46        HardwarePixelBuffer(0, 0, 0, PF_UNKNOWN, usage, false, false),
47        mpDev(0),
48        mSurface(0), mVolume(0), mTempSurface(0), mTempVolume(0),
49        mDoMipmapGen(0), mHWMipmaps(0), mMipTex(0)
50{
51}
52D3D9HardwarePixelBuffer::~D3D9HardwarePixelBuffer()
53{
54        destroyRenderTextures();
55}
56//----------------------------------------------------------------------------- 
57void D3D9HardwarePixelBuffer::bind(IDirect3DDevice9 *dev, IDirect3DSurface9 *surface, bool update)
58{
59        mpDev = dev;
60        mSurface = surface;
61       
62        D3DSURFACE_DESC desc;
63        if(mSurface->GetDesc(&desc) != D3D_OK)
64                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Could not get surface information",
65                 "D3D9HardwarePixelBuffer::D3D9HardwarePixelBuffer");
66        mWidth = desc.Width;
67        mHeight = desc.Height;
68        mDepth = 1;
69        mFormat = D3D9Mappings::_getPF(desc.Format);
70        // Default
71        mRowPitch = mWidth;
72        mSlicePitch = mHeight*mWidth;
73        mSizeInBytes = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);
74
75        if(mUsage & TU_RENDERTARGET)
76                createRenderTextures(update);
77}
78//-----------------------------------------------------------------------------
79void D3D9HardwarePixelBuffer::bind(IDirect3DDevice9 *dev, IDirect3DVolume9 *volume, bool update)
80{
81        mpDev = dev;
82        mVolume = volume;
83       
84        D3DVOLUME_DESC desc;
85        if(mVolume->GetDesc(&desc) != D3D_OK)
86                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Could not get volume information",
87                 "D3D9HardwarePixelBuffer::D3D9HardwarePixelBuffer");
88        mWidth = desc.Width;
89        mHeight = desc.Height;
90        mDepth = desc.Depth;
91        mFormat = D3D9Mappings::_getPF(desc.Format);
92        // Default
93        mRowPitch = mWidth;
94        mSlicePitch = mHeight*mWidth;
95        mSizeInBytes = PixelUtil::getMemorySize(mWidth, mHeight, mDepth, mFormat);
96
97        if(mUsage & TU_RENDERTARGET)
98                createRenderTextures(update);
99}
100//----------------------------------------------------------------------------- 
101// Util functions to convert a D3D locked box to a pixel box
102void fromD3DLock(PixelBox &rval, const D3DLOCKED_RECT &lrect)
103{
104        rval.rowPitch = lrect.Pitch / PixelUtil::getNumElemBytes(rval.format);
105        rval.slicePitch = rval.rowPitch * rval.getHeight();
106        assert((lrect.Pitch % PixelUtil::getNumElemBytes(rval.format))==0);
107        rval.data = lrect.pBits;
108}
109void fromD3DLock(PixelBox &rval, const D3DLOCKED_BOX &lbox)
110{
111        rval.rowPitch = lbox.RowPitch / PixelUtil::getNumElemBytes(rval.format);
112        rval.slicePitch = lbox.SlicePitch / PixelUtil::getNumElemBytes(rval.format);
113        assert((lbox.RowPitch % PixelUtil::getNumElemBytes(rval.format))==0);
114        assert((lbox.SlicePitch % PixelUtil::getNumElemBytes(rval.format))==0);
115        rval.data = lbox.pBits;
116}
117// Convert Ogre integer Box to D3D rectangle
118RECT toD3DRECT(const Box &lockBox)
119{
120        RECT prect;
121        assert(lockBox.getDepth() == 1);
122        prect.left = lockBox.left;
123        prect.right = lockBox.right;
124        prect.top = lockBox.top;
125        prect.bottom = lockBox.bottom;
126        return prect;
127}
128// Convert Ogre integer Box to D3D box
129D3DBOX toD3DBOX(const Box &lockBox)
130{
131        D3DBOX pbox;
132        pbox.Left = lockBox.left;
133        pbox.Right = lockBox.right;
134        pbox.Top = lockBox.top;
135        pbox.Bottom = lockBox.bottom;
136        pbox.Front = lockBox.front;
137        pbox.Back = lockBox.back;
138        return pbox;
139}
140// Convert Ogre pixelbox extent to D3D rectangle
141RECT toD3DRECTExtent(const PixelBox &lockBox)
142{
143        RECT prect;
144        assert(lockBox.getDepth() == 1);
145        prect.left = 0;
146        prect.right = lockBox.getWidth();
147        prect.top = 0;
148        prect.bottom = lockBox.getHeight();
149        return prect;
150}
151// Convert Ogre pixelbox extent to D3D box
152D3DBOX toD3DBOXExtent(const PixelBox &lockBox)
153{
154        D3DBOX pbox;
155        pbox.Left = 0;
156        pbox.Right = lockBox.getWidth();
157        pbox.Top = 0;
158        pbox.Bottom = lockBox.getHeight();
159        pbox.Front = 0;
160        pbox.Back = lockBox.getDepth();
161        return pbox;
162}
163//----------------------------------------------------------------------------- 
164PixelBox D3D9HardwarePixelBuffer::lockImpl(const Image::Box lockBox,  LockOptions options)
165{
166        // Check for misuse
167        if(mUsage & TU_RENDERTARGET)
168                OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "DirectX does not allow locking of or directly writing to RenderTargets. Use blitFromMemory if you need the contents.",
169                        "D3D9HardwarePixelBuffer::lockImpl");   
170        // Set extents and format
171        PixelBox rval(lockBox, mFormat);
172        // Set locking flags according to options
173        DWORD flags = 0;
174        switch(options)
175        {
176        case HBL_DISCARD:
177                // D3D only likes D3DLOCK_DISCARD if you created the texture with D3DUSAGE_DYNAMIC
178                // debug runtime flags this up, could cause problems on some drivers
179                if (mUsage & HBU_DYNAMIC)
180                        flags |= D3DLOCK_DISCARD;
181                break;
182        case HBL_READ_ONLY:
183                flags |= D3DLOCK_READONLY;
184                break;
185        default:
186                break;
187        };
188       
189        if(mSurface)
190        {
191                // Surface
192                D3DLOCKED_RECT lrect; // Filled in by D3D
193                HRESULT hr;
194
195                if (lockBox.left == 0 && lockBox.top == 0
196                        && lockBox.right == mWidth && lockBox.bottom == mHeight)
197                {
198                        // Lock whole surface
199                        hr = mSurface->LockRect(&lrect, NULL, flags);
200                }
201                else
202                {
203                        RECT prect = toD3DRECT(lockBox); // specify range to lock
204                        hr = mSurface->LockRect(&lrect, &prect, flags);
205                }
206                if (FAILED(hr))         
207                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Surface locking failed",
208                                "D3D9HardwarePixelBuffer::lockImpl");
209                fromD3DLock(rval, lrect);
210        }
211        else
212        {
213                // Volume
214                D3DBOX pbox = toD3DBOX(lockBox); // specify range to lock
215                D3DLOCKED_BOX lbox; // Filled in by D3D
216               
217                if(mVolume->LockBox(&lbox, &pbox, flags) != D3D_OK)
218                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Volume locking failed",
219                                "D3D9HardwarePixelBuffer::lockImpl");
220                fromD3DLock(rval, lbox);
221        }
222
223        return rval;
224}
225//----------------------------------------------------------------------------- 
226void D3D9HardwarePixelBuffer::unlockImpl(void)
227{
228        if(mSurface)
229        {
230                // Surface
231                mSurface->UnlockRect();
232        } else {
233                // Volume
234                mVolume->UnlockBox();
235        }
236        if(mDoMipmapGen)
237                _genMipmaps();
238}
239//----------------------------------------------------------------------------- 
240void D3D9HardwarePixelBuffer::blit(const HardwarePixelBufferSharedPtr &rsrc, const Image::Box &srcBox, const Image::Box &dstBox)
241{
242        D3D9HardwarePixelBuffer *src = static_cast<D3D9HardwarePixelBuffer*>(rsrc.getPointer());
243        if(mSurface && src->mSurface)
244        {
245                // Surface-to-surface
246                RECT dsrcRect = toD3DRECT(srcBox);
247                RECT ddestRect = toD3DRECT(dstBox);
248                // D3DXLoadSurfaceFromSurface
249                if(D3DXLoadSurfaceFromSurface(
250                        mSurface, NULL, &ddestRect,
251                        src->mSurface, NULL, &dsrcRect,
252                         D3DX_DEFAULT, 0) != D3D_OK)
253                {
254                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3DXLoadSurfaceFromSurface failed",
255                                "D3D9HardwarePixelBuffer::blit");
256                }
257        }
258        else if(mVolume && src->mVolume)
259        {
260                // Volume-to-volume
261                D3DBOX dsrcBox = toD3DBOX(srcBox);
262                D3DBOX ddestBox = toD3DBOX(dstBox);
263               
264                // D3DXLoadVolumeFromVolume
265                if(D3DXLoadVolumeFromVolume(
266                        mVolume, NULL, &ddestBox,
267                        src->mVolume, NULL, &dsrcBox,
268                         D3DX_DEFAULT, 0) != D3D_OK)
269                {
270                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3DXLoadVolumeFromVolume failed",
271                                "D3D9HardwarePixelBuffer::blit");
272                }
273        }
274        else
275        {
276        // Software fallback   
277                HardwarePixelBuffer::blit(rsrc, srcBox, dstBox);
278        }
279}
280//----------------------------------------------------------------------------- 
281void D3D9HardwarePixelBuffer::blitFromMemory(const PixelBox &src, const Image::Box &dstBox)
282{
283        // for scoped deletion of conversion buffer
284        MemoryDataStreamPtr buf;
285        PixelBox converted = src;
286
287        // convert to pixelbuffer's native format if necessary
288        if (D3D9Mappings::_getPF(src.format) == D3DFMT_UNKNOWN)
289        {
290                buf.bind(new MemoryDataStream(
291                        PixelUtil::getMemorySize(src.getWidth(), src.getHeight(), src.getDepth(),
292                                                                                mFormat)));
293                converted = PixelBox(src.getWidth(), src.getHeight(), src.getDepth(), mFormat, buf->getPtr());
294                PixelUtil::bulkPixelConversion(src, converted);
295        }
296
297        if(mSurface)
298        {
299                RECT destRect, srcRect;
300                srcRect = toD3DRECTExtent(converted);
301                destRect = toD3DRECT(dstBox);
302               
303                if(D3DXLoadSurfaceFromMemory(mSurface, NULL, &destRect,
304                        converted.data, D3D9Mappings::_getPF(converted.format),
305                        converted.rowPitch * PixelUtil::getNumElemBytes(converted.format),
306                        NULL, &srcRect, D3DX_DEFAULT, 0) != D3D_OK)
307                {
308                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3DXLoadSurfaceFromMemory failed",
309                                "D3D9HardwarePixelBuffer::blitFromMemory");
310                }
311        }
312        else
313        {
314                D3DBOX destBox, srcBox;
315                srcBox = toD3DBOXExtent(converted);
316                destBox = toD3DBOX(dstBox);
317               
318                if(D3DXLoadVolumeFromMemory(mVolume, NULL, &destBox,
319                        converted.data, D3D9Mappings::_getPF(converted.format),
320                        converted.rowPitch * PixelUtil::getNumElemBytes(converted.format),
321                        converted.slicePitch * PixelUtil::getNumElemBytes(converted.format),
322                        NULL, &srcBox, D3DX_DEFAULT, 0) != D3D_OK)
323                {
324                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3DXLoadSurfaceFromMemory failed",
325                                "D3D9HardwarePixelBuffer::blitFromMemory");
326                }
327        }
328        if(mDoMipmapGen)
329                _genMipmaps();
330}
331//----------------------------------------------------------------------------- 
332void D3D9HardwarePixelBuffer::blitToMemory(const Image::Box &srcBox, const PixelBox &dst)
333{
334        // Decide on pixel format of temp surface
335        PixelFormat tmpFormat = mFormat;
336        if(D3D9Mappings::_getPF(dst.format) != D3DFMT_UNKNOWN)
337        {
338                tmpFormat = dst.format;
339        }
340        if(mSurface)
341        {
342                assert(srcBox.getDepth() == 1 && dst.getDepth() == 1);
343                // Create temp texture
344                IDirect3DTexture9 *tmp;
345                IDirect3DSurface9 *surface;
346       
347                if(D3DXCreateTexture(
348                        mpDev,
349                        dst.getWidth(), dst.getHeight(),
350                        1, // 1 mip level ie topmost, generate no mipmaps
351                        0, D3D9Mappings::_getPF(tmpFormat), D3DPOOL_SCRATCH,
352                        &tmp
353                        ) != D3D_OK)
354                {
355                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Create temporary texture failed",
356                                "D3D9HardwarePixelBuffer::blitToMemory");
357                }
358                if(tmp->GetSurfaceLevel(0, &surface) != D3D_OK)
359                {
360                        tmp->Release();
361                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Get surface level failed",
362                                "D3D9HardwarePixelBuffer::blitToMemory");
363                }
364                // Copy texture to this temp surface
365                RECT destRect, srcRect;
366                srcRect = toD3DRECT(srcBox);
367                destRect = toD3DRECTExtent(dst);
368               
369                if(D3DXLoadSurfaceFromSurface(
370                        surface, NULL, &destRect,
371                        mSurface, NULL, &srcRect,
372                         D3DX_DEFAULT, 0) != D3D_OK)
373                {
374                        surface->Release();
375                        tmp->Release();
376                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3DXLoadSurfaceFromSurface failed",
377                                "D3D9HardwarePixelBuffer::blitToMemory");
378                }
379                // Lock temp surface and copy it to memory
380                D3DLOCKED_RECT lrect; // Filled in by D3D
381                if(surface->LockRect(&lrect, NULL,  D3DLOCK_READONLY) != D3D_OK)
382                {
383                        surface->Release();
384                        tmp->Release();
385                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "surface->LockRect",
386                                "D3D9HardwarePixelBuffer::blitToMemory");
387                }
388                // Copy it
389                PixelBox locked(dst.getWidth(), dst.getHeight(), dst.getDepth(), tmpFormat);
390                fromD3DLock(locked, lrect);
391                PixelUtil::bulkPixelConversion(locked, dst);
392                surface->UnlockRect();
393                // Release temporary surface and texture
394                surface->Release();
395                tmp->Release();
396        }
397        else
398        {
399                // Create temp texture
400                IDirect3DVolumeTexture9 *tmp;
401                IDirect3DVolume9 *surface;
402       
403                if(D3DXCreateVolumeTexture(
404                        mpDev,
405                        dst.getWidth(), dst.getHeight(), dst.getDepth(), 0,
406                        0, D3D9Mappings::_getPF(tmpFormat), D3DPOOL_SCRATCH,
407                        &tmp
408                        ) != D3D_OK)
409                {
410                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Create temporary texture failed",
411                                "D3D9HardwarePixelBuffer::blitToMemory");
412                }
413                if(tmp->GetVolumeLevel(0, &surface) != D3D_OK)
414                {
415                        tmp->Release();
416                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "Get volume level failed",
417                                "D3D9HardwarePixelBuffer::blitToMemory");
418                }
419                // Volume
420                D3DBOX ddestBox, dsrcBox;
421                ddestBox = toD3DBOXExtent(dst);
422                dsrcBox = toD3DBOX(srcBox);
423               
424                if(D3DXLoadVolumeFromVolume(
425                        surface, NULL, &ddestBox,
426                        mVolume, NULL, &dsrcBox,
427                         D3DX_DEFAULT, 0) != D3D_OK)
428                {
429                        surface->Release();
430                        tmp->Release();
431                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "D3DXLoadVolumeFromVolume failed",
432                                "D3D9HardwarePixelBuffer::blitToMemory");
433                }
434                // Lock temp surface and copy it to memory
435                D3DLOCKED_BOX lbox; // Filled in by D3D
436                if(surface->LockBox(&lbox, NULL,  D3DLOCK_READONLY) != D3D_OK)
437                {
438                        surface->Release();
439                        tmp->Release();
440                        OGRE_EXCEPT(Exception::ERR_RENDERINGAPI_ERROR, "surface->LockBox",
441                                "D3D9HardwarePixelBuffer::blitToMemory");
442                }
443                // Copy it
444                PixelBox locked(dst.getWidth(), dst.getHeight(), dst.getDepth(), tmpFormat);
445                fromD3DLock(locked, lbox);
446                PixelUtil::bulkPixelConversion(locked, dst);
447                surface->UnlockBox();
448                // Release temporary surface and texture
449                surface->Release();
450                tmp->Release();
451        }
452}
453//----------------------------------------------------------------------------- 
454void D3D9HardwarePixelBuffer::_genMipmaps()
455{
456        assert(mMipTex);
457        // Mipmapping
458        if (mHWMipmaps)
459        {
460                // Hardware mipmaps
461                mMipTex->GenerateMipSubLevels();
462        }
463        else
464        {
465                // Software mipmaps
466                if( D3DXFilterTexture( mMipTex, NULL, D3DX_DEFAULT, D3DX_DEFAULT ) != D3D_OK )
467                {
468                        OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR,
469                        "Failed to filter texture (generate mipmaps)",
470                         "D3D9HardwarePixelBuffer::_genMipmaps" );
471                }
472        }
473
474}
475//-----------------------------------------------------------------------------
476void D3D9HardwarePixelBuffer::_setMipmapping(bool doMipmapGen, bool HWMipmaps, IDirect3DBaseTexture9 *mipTex)
477{
478        mDoMipmapGen = doMipmapGen;
479        mHWMipmaps = HWMipmaps;
480        mMipTex = mipTex;
481}
482//-----------------------------------------------------------------------------   
483RenderTexture *D3D9HardwarePixelBuffer::getRenderTarget(size_t zoffset)
484{
485    assert(mUsage & TU_RENDERTARGET);
486    assert(zoffset < mDepth);
487    return mSliceTRT[zoffset];
488}
489//-----------------------------------------------------------------------------   
490void D3D9HardwarePixelBuffer::createRenderTextures(bool update)
491{
492    if (update)
493    {
494        assert(mSliceTRT.size() == mDepth);
495        for (SliceTRT::const_iterator it = mSliceTRT.begin(); it != mSliceTRT.end(); ++it)
496        {
497            D3D9RenderTexture *trt = static_cast<D3D9RenderTexture*>(*it);
498            trt->rebind(this);
499        }
500        return;
501    }
502
503        destroyRenderTextures();
504        if(!mSurface)
505        {
506                OGRE_EXCEPT( Exception::ERR_RENDERINGAPI_ERROR,
507                        "Rendering to 3D slices not supported yet for Direct3D",
508                         "D3D9HardwarePixelBuffer::createRenderTexture");
509        }
510        // Create render target for each slice
511    mSliceTRT.reserve(mDepth);
512        assert(mDepth==1);
513    for(size_t zoffset=0; zoffset<mDepth; ++zoffset)
514    {
515        String name;
516                name = "rtt/"+Ogre::StringConverter::toString((size_t)mSurface);
517               
518        RenderTexture *trt = new D3D9RenderTexture(name, this);
519        mSliceTRT.push_back(trt);
520        Root::getSingleton().getRenderSystem()->attachRenderTarget(*trt);
521    }
522}
523//-----------------------------------------------------------------------------   
524void D3D9HardwarePixelBuffer::destroyRenderTextures()
525{
526        if(mSliceTRT.empty())
527                return;
528        // Delete all render targets that are not yet deleted via _clearSliceRTT
529    for(size_t zoffset=0; zoffset<mDepth; ++zoffset)
530    {
531        if(mSliceTRT[zoffset])
532            Root::getSingleton().getRenderSystem()->destroyRenderTarget(mSliceTRT[zoffset]->getName());
533    }
534}
535
536};
Note: See TracBrowser for help on using the repository browser.