I have a class that represents an gui-element, that has method to set an image on it's background:
class Element
{
public:
ID2D1Bitmap *image;
ID2D1DeviceContext *target;
int x, y, width, height;
Element(ID2D1DeviceContext *target, int x, int y, int width, int height)
{
image = nullptr;
this->target = target;
this->x = x; this->y = y; this->width = width; this->height = height;
}
void Render()
{
if(image)
target->DrawBitmap(image, D2D1::RectF(x, y, x + width, y + height));
}
void setBackgroundImage(const wchar_t* path)
{
if (!path || wcslen(path) == 0)
return;
IWICBitmapFrameDecode* d2dBmpSrc = nullptr;
IWICBitmapDecoder* d2dDecoder = nullptr;
d2dWICFactory->CreateDecoderFromFilename(path, NULL, GENERIC_READ,
WICDecodeMetadataCacheOnLoad, &d2dDecoder);
if (d2dDecoder)
{
d2dDecoder->GetFrame(0, &d2dBmpSrc);
if (d2dBmpSrc)
{
d2dWICFactory->CreateFormatConverter(&d2dConverter2);
d2dConverter2->Initialize(d2dBmpSrc, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut);
ID2D1Bitmap *temp = nullptr;
tar->CreateBitmapFromWicBitmap(d2dConverter2, NULL, &temp);
if (temp)
{
D2D1_SIZE_F si = temp->GetSize();
tar->CreateBitmap(D2D1::SizeU(si.width, si.height), 0, 0, D2D1::BitmapProperties(
D2D1::PixelFormat(DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE::D2D1_ALPHA_MODE_PREMULTIPLIED)
), &image);
image->CopyFromBitmap(0, temp, 0);
SafeRelease(&temp);
}
}
}
SafeRelease(&d2dDecoder);
SafeRelease(&d2dBmpSrc);
SafeRelease(&d2dConverter2);
}
~Element(){SafeRelease(&image);}
}*object[100] = {NULL};
int main()
{
ID2D1Factory *factory = nullptr;
D2D1CreateFactory(D2D1_FACTORY_TYPE::D2D1_FACTORY_TYPE_MULTI_THREADED, &factory);
ID2D1DeviceContext *target = ObtainDeviceContext(factory);
object[0] = new Element(target, 0, 0, 100, 100);
object[0]->setBackgroundImage(L"img.png");
for(;;) // But in reality here also is Windows message loop with Dispatch message
{
target->BeginDraw();
target->Clear(D2D1::ColorF(1, 1, 1));
for(int i = 0; i < 100 && object[i]; i++)
object[i]->Render();
target->EndDraw();
}
return 0;
}
All works fine, but the problem, is that loading an image is obviously hangs the program.
Unfortunately, my asynchronous c++ skills are almost empty. I tried to just change method to this:
void Element::setBackgroundImage(const wchar_t*path)
{
thread th(LoadImage(this, path)); th.detach();
}
And jsut bring all code from the method to global function, with additional first argument - LoadImage(Object*,const wchar_t*);
Unfortunately, it immediately crashes. Then I created global variable mutex mu and placed mu.lock() and mu.unlock() as first and last line in LoadImage correspond. Still crashes.
Maybe I also need to lock in Render, and probably on destructor? By the way, what will happen if destructor will try to release image variable at time when it is locked by another thread? It will not be free, and hence memory leak?
Can someone please explain at least general conception of using asynchronous c++ programming for my case? Not thread::join, I need the main thread be going.
Also I would appreciate if You explain how to properly make render loop running in asynchronous thread.
First off, your code is far from a minimal reproducible example. But then again, I've never touched Direct2D before, and I still managed to get it working.
Anyway, it doesn't matter what you do, you'll have to load the image before you're able to render it. Since you used browsers as an example in the comments, what they do is indeed fetch and load files on separate threads, but before they're loaded and in memory, they're rendering placeholders or nothing at all.
Loading the image in a separate thread and locking a mutex in the render function is the same as not using any threads at all (functionally, at least. The main thread will still block in render while the image is being loaded). Really, what you tried before, with this:
void Element::setBackgroundImage(const wchar_t*path)
{
thread th(LoadImage(this, path)); th.detach();
}
should work, (in my testing even with a D2D1_FACTORY_TYPE_SINGLE_THREADED factory), since you're not rendering the element if image == nullptr, which acts a sort of lock. Using a proper bool loaded state variable would be even better, but it still works.
You just misused the std::thread constructor syntax, since you're handing it the return value of LoadImage with the arguments this and path, which is almost certainly not a function pointer or lambda, given that your program is crashing (In simple words: You're calling the function instead of passing it in as an argument).
Creating a std::thread calling Element::setBackgroundImage properly:
class Element
{
public:
...
void asyncSetBackgroundImage(const wchar_t* path)
{
std::thread thread(
&Element::setBackgroundImage,
this,
path
);
thread.detach();
}
...
};
Also I would appreciate if You explain how to properly make render loop running in asynchronous thread.
It's really as simple as handling the Win32 window message loop on the main thread, while doing the rendering on a separate thread.
bool render_state = true;
std::thread render_thread(
[&]()
{
while (render_state)
{
target->BeginDraw();
target->Clear(D2D1::ColorF(1, 1, 1));
for(int i = 0; i < 100 && object[i]; i++)
object[i]->Render();
target->EndDraw();
}
}
);
render_thread.detach();
while (window.win32_loop_iteration())
{ }
render_state = false;
This is where you might want to use a mutex, to synchronize the start and stop of the loop, but aside from that, this is enough.
Also, a (mostly) minimally reproducible example; all that's missing is the WINDOW::Window class, which can create a Win32 window among other things:
#include <d2d1.h>
#include <d2d1_1.h>
#include <wincodec.h>
#include "window/window.hpp"
#include <thread>
template <class T> void SafeRelease(T **ppT)
{
if (*ppT)
{
(*ppT)->Release();
*ppT = NULL;
}
}
IWICImagingFactory* d2dWICFactory = nullptr;
class Element
{
public:
ID2D1Bitmap *image;
ID2D1DeviceContext *target;
int x, y, width, height;
Element(ID2D1DeviceContext *target, int x, int y, int width, int height)
{
image = nullptr;
this->target = target;
this->x = x; this->y = y; this->width = width; this->height = height;
}
void Render()
{
if(image)
target->DrawBitmap(image, D2D1::RectF(x, y, x + width, y + height));
}
void setBackgroundImage(const wchar_t* path)
{
if (!path || wcslen(path) == 0)
return;
IWICBitmapFrameDecode* d2dBmpSrc = nullptr;
IWICBitmapDecoder* d2dDecoder = nullptr;
IWICFormatConverter* d2dConverter2 = nullptr;
d2dWICFactory->CreateDecoderFromFilename(path, NULL, GENERIC_READ,
WICDecodeMetadataCacheOnLoad, &d2dDecoder);
if (d2dDecoder)
{
d2dDecoder->GetFrame(0, &d2dBmpSrc);
if (d2dBmpSrc)
{
d2dWICFactory->CreateFormatConverter(&d2dConverter2);
d2dConverter2->Initialize(d2dBmpSrc, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteTypeMedianCut);
ID2D1Bitmap *temp = nullptr;
target->CreateBitmapFromWicBitmap(d2dConverter2, NULL, &temp);
if (temp)
{
D2D1_SIZE_F si = temp->GetSize();
target->CreateBitmap(D2D1::SizeU(si.width, si.height), 0, 0, D2D1::BitmapProperties(
D2D1::PixelFormat(DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE::D2D1_ALPHA_MODE_PREMULTIPLIED)
), &image);
image->CopyFromBitmap(0, temp, 0);
SafeRelease(&temp);
}
}
}
SafeRelease(&d2dDecoder);
SafeRelease(&d2dBmpSrc);
SafeRelease(&d2dConverter2);
}
void asyncSetBackgroundImage(const wchar_t* path)
{
std::thread thread(
&Element::setBackgroundImage,
this,
path
);
thread.detach();
}
~Element()
{
SafeRelease(&image);
}
};
Element* object[100] = { nullptr };
int main(
int argument_count,
char** arguments
)
{
CoInitialize(
NULL
);
ID2D1Factory1 *factory = nullptr;
D2D1CreateFactory(D2D1_FACTORY_TYPE::D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory);
ID2D1HwndRenderTarget* render_target = nullptr;
D2D1_RENDER_TARGET_PROPERTIES properties = {};
properties.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
properties.pixelFormat = D2D1::PixelFormat(DXGI_FORMAT::DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE::D2D1_ALPHA_MODE_IGNORE);
properties.dpiX = 0;
properties.dpiY = 0;
properties.usage = D2D1_RENDER_TARGET_USAGE::D2D1_RENDER_TARGET_USAGE_NONE;
properties.minLevel = D2D1_FEATURE_LEVEL::D2D1_FEATURE_LEVEL_DEFAULT;
WINDOW::Window window = {};
window.create();
window.show();
D2D1_HWND_RENDER_TARGET_PROPERTIES hwnd_properties = {};
hwnd_properties.hwnd = window.win32_handle_get();
hwnd_properties.pixelSize.width = window.size_x_get();
hwnd_properties.pixelSize.height = window.size_y_get();
hwnd_properties.presentOptions = D2D1_PRESENT_OPTIONS::D2D1_PRESENT_OPTIONS_NONE;
factory->CreateHwndRenderTarget(
&properties,
&hwnd_properties,
&render_target
);
ID2D1DeviceContext *target = reinterpret_cast<ID2D1DeviceContext*>(render_target);
CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory),
reinterpret_cast<LPVOID*>(&d2dWICFactory)
);
object[0] = new Element(target, 0, 0, 100, 100);
object[0]->asyncSetBackgroundImage(L"img.png");
while (window.win32_loop_iteration())
{
target->BeginDraw();
target->Clear(D2D1::ColorF(1, 1, 1));
for(int i = 0; i < 100 && object[i]; i++)
object[i]->Render();
target->EndDraw();
}
return 0;
}
Related
I wrote some solution to draw gifs, using Direct2D GIF sample:
// somewhere in render loop
IWICBitmapFrameDecode* frame = nullptr;
IWICFormatConverter* converter = nullptr;
gifDecoder->GetFrame(current_frame, &frame);
if (frame)
{
d2dWICFactory->CreateFormatConverter(&converter);
if (converter)
{
ID2D1Bitmap* temp = nullptr;
converter->Initialize(frame, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteType::WICBitmapPaletteTypeCustom);
tar->CreateBitmapFromWicBitmap(converter, NULL, &temp);
scale->SetValue(D2D1_SCALE_PROP_SCALE, D2D1::Vector2F(1, 1));
scale->SetInput(0, temp);
target->DrawImage(scale);
SafeRelease(&temp);
}
}
SafeRelease(&frame);
SafeRelease(&converter);
Where gifDecoder is obtained this way:
d2dWICFactory->CreateDecoderFromFilename(pathToGif, NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &gifDecoder);
But in my program almost with all gifs, all frames, except the first one, for some reason have horizontal transparent lines. Obviously, when I view the same gif in browser or in another program there are no that holes.
I tried to change pixel format, pallet type, but that glitches are still there.
What do I do wrong?
Basic steps:
On image load, in case of gif, for caching purposes store not all frames as ready to draw ID2D1Bitmaps but only the image's decoder. Every time decode the frame, get bitmap and draw it. At least, at first animation loop frames bitmaps and metadata (again, for each frame) can be cached.
For each gif create compatible target with the size of gif screen (obtained from metadata) for composing.
Compose animation on render: get metadata for current frame -> if current frame has disposal = true, clear compose target -> draw current frame to compose target (even if disposal true) -> draw compose target to render target,
Note, that frames may have different sizes and even offsets.
Approximate code:
ID2D1DeviceContext *renderTarget;
class GIF
{
ID2D1BitmapRenderTarget *compose;
IWICBitmapDecoder *decoder; // it seems like precache all frames costs too much time, it will be faster to obtain each frame each time (maybe cache during first loop)
float naturalWidth; // gif screen width
float naturalHeight; // gif screen height
int framesCount;
int currentFrame;
unsigned int lastFrameEpoch;
int x;
int y;
int width; // image width needed to be drawn
int height; // image height
float fw; // scale factor width;
float fh; // scale factor height
GIF(const wchar_t *path, int x, int y, int width, int height)
{
// Init, using WIC obtain here image's decoder, naturalWidth, naturalHeight
// framesCount and other optional stuff like loop information
// using IWICMetadataQueryReader obtained from the whole image,
// not from zero frame
compose = nullptr;
currentFrame = 0;
lastFrameEpoch = epoch(); // implement Your millisecond function
Resize(width, height);
}
void Resize(int width, int height)
{
this->width = width;
this->height = height;
// calculate scale factors
fw = width / naturalWidth;
fh = height / naturalHeight;
if(compose == nullptr)
{
renderTarget->CreateCompatibleRenderTarget(D2D1::SizeF(naturalWidth, naturalHeight), &compose);
compose->Clear(D2D1::ColorF(0,0,0,0));
}
}
void Render()
{
IWICBitmapFrameDecode* frame = nullptr;
decoder->GetFrame(currentFrame, &frame);
IWICFormatConverter* converter = nullptr;
d2dWICFactory->CreateFormatConverter(&converter);
converter->Initialize(frame, GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone, NULL, 0.f, WICBitmapPaletteType::WICBitmapPaletteTypeCustom);
IWICMetadataQueryReader* reader = nullptr;
frame->GetMetadataQueryReader(&reader);
PROPVARIANT propValue;
PropVariantInit(&propValue);
char disposal = 0;
float l = 0, t = 0; // frame offsets (may have)
HRESULT hr = S_OK;
reader->GetMetadataByName(L"/grctlext/Delay", &propValue);
if (SUCCEEDED((propValue.vt == VT_UI2 ? S_OK : E_FAIL)))
{
UINT frameDelay = 0;
UIntMult(propValue.uiVal, 10, &fr);
frameDelay = fr;
if (frameDelay < 16)
{
frameDelay = 16;
}
if(epoch() - lastFrameEpoch < frameDelay)
{
SafeRelease(&reader);
SafeRelease(&frame);
SafeRelease(&converter);
return;
}
}
if (SUCCEEDED(reader->GetMetadataByName(
L"/grctlext/Disposal",
&propValue)))
{
hr = (propValue.vt == VT_UI1) ? S_OK : E_FAIL;
if (SUCCEEDED(hr))
{
disposal = propValue.bVal;
}
}
PropVariantClear(&propValue);
{
hr = reader->GetMetadataByName(L"/imgdesc/Left", &propValue);
if (SUCCEEDED(hr))
{
hr = (propValue.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
l = static_cast<FLOAT>(propValue.uiVal);
}
PropVariantClear(&propValue);
}
}
{
hr = reader->GetMetadataByName(L"/imgdesc/Top", &propValue);
if (SUCCEEDED(hr))
{
hr = (propValue.vt == VT_UI2 ? S_OK : E_FAIL);
if (SUCCEEDED(hr))
{
t = static_cast<FLOAT>(propValue.uiVal);
}
PropVariantClear(&propValue);
}
}
renderTarget->CreateBitmapFromWicBitmap(converter, NULL, &temp);
compose->BeginDraw();
if (disposal == 2)
compose->Clear(D2D1::ColorF(0, 0, 0, 0));
auto ss = temp->GetSize();
compose->DrawBitmap(temp, D2D1::RectF(l, t, l + ss.width, t + ss.height));
compose->EndDraw();
ID2D1Bitmap* composition = nullptr;
compose->GetBitmap(&composition);
// You need to create scale effect to have antialised resizing
scale->SetValue(D2D1_SCALE_PROP_SCALE, D2D1::Vector2F(fw, fh));
scale->SetInput(0, composition);
auto p = D2D1::Point2F(x, y);
renderTarget->DrawImage(iscale, p);
SafeRelease(&temp);
SafeRelease(&composition);
SafeRelease(&reader);
SafeRelease(&frame);
SafeRelease(&converter);
}
}*gif[100] = {nullptr};
inline void Render()
{
renderTarget->BeginDraw();
for(int i = 0; i < 100 && gif[i] != nullptr; i++)
gif[i]->Render();
renderTarget->EndDraw();
}
I'm trying to draw CEF buffer (returned on OnPaint) to D3D9 texture of the game, and game randomly premanently freezes. I figured out that code provided below is the reason of the game freeze, but still can't understand. What did I miss?
// To create texture I use this code
LPDIRECT3DTEXTURE9 tWebPNG;
D3DXCreateTexture(device, width, height, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &tWebPNG);
// And the problem in that method
void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height)
{
D3DLOCKED_RECT LockedRect;
D3DSURFACE_DESC SurfaceDesc;
IDirect3DSurface9* pSurface;
tWebPNG->GetSurfaceLevel(0, &pSurface);
pSurface->GetDesc(&SurfaceDesc);
pSurface->LockRect(&LockedRect, nullptr, 0);
auto dest = (unsigned char*)LockedRect.pBits;
auto src = (const char*)buffer;
for (int i = 0; i < height; ++i)
{
memcpy(dest, src, width * 4);
dest += LockedRect.Pitch;
src += width * 4;
}
pSurface->UnlockRect();
}
To be clear: CEF is rendered as expected, it have no errors and here is just texture render problem. Hope to get any help
After discussing in comments, I have modified my code a bit:
// Modified OnPaint to work with mutaxes
void OnPaint(CefRefPtr<CefBrowser> browser, PaintElementType type, const RectList& dirtyRects, const void* buffer, int width, int height)
{
{
std::lock_guard<std::mutex> lock(m_RenderData.dataMutex);
// Store render data
m_RenderData.buffer = buffer;
m_RenderData.width = width;
m_RenderData.height = height;
m_RenderData.dirtyRects = dirtyRects;
m_RenderData.changed = true;
}
// Wait for the main thread to handle drawing the texture
std::unique_lock<std::mutex> lock(m_RenderData.cvMutex);
m_RenderData.cv.wait(lock);
}
// This method is intended to draw into d3d9 layer
void Browser::draw()
{
std::lock_guard<std::mutex> lock(m_RenderData.dataMutex);
IDirect3DSurface9* pSurface;
tWebPNG->GetSurfaceLevel(0, &pSurface);
if (m_RenderData.changed)
{
// Lock surface
D3DLOCKED_RECT LockedRect;
if (FAILED(pSurface->LockRect(&LockedRect, nullptr, 0))) {
m_RenderData.cv.notify_all();
return;
}
// Update changed state
m_RenderData.changed = false;
D3DSURFACE_DESC SurfaceDesc;
IDirect3DSurface9* pSurface;
tWebPNG->GetSurfaceLevel(0, &pSurface);
pSurface->GetDesc(&SurfaceDesc);
pSurface->LockRect(&LockedRect, nullptr, 0);
auto dest = (unsigned char*)LockedRect.pBits;
auto src = (const char*)m_RenderData.buffer;
for (int i = 0; i < height; ++i)
{
memcpy(dest, src, width * 4);
dest += LockedRect.Pitch;
src += width * 4;
}
// Unlock surface
pSurface->UnlockRect();
}
D3DXVECTOR3* vector = new D3DXVECTOR3(0, 0, 0);
sprite->Begin(D3DXSPRITE_ALPHABLEND);
sprite->Draw(tWebPNG, NULL, NULL, vector, 0xFFFFFFFF);
sprite->End();
m_RenderData.cv.notify_all();
}
As discussed above, the paint event (and override method) are both called on the CefBrowser UI thread, and locking the same texture multiple times before it gets released will deadlock your entire D3D context.
The fix is to separate the paint event handler (which is responsible for saving the rendered Chrome image to an internal buffer) from the D3D render thread (which is responsible for uploading the internal buffer to the D3D texture and rendering with it).
I cannot convert a GDI+ bitmap to base 64 in C++
I have so far:
Downloaded and included this library: https://github.com/ReneNyffenegger/cpp-base64
Written the function that you can see below.
Called it, passing in a bitmap that I know has data. I know that the bitmap has data because I am using in another function called directly after this one.
The problem is that the charPixels array is always full of zeros.
Secondly can you please explain to me what the safe way of unlocking the bits is. I fear that if I just do it in the finally, if the bits aren't actually locked at that point I will get an exception.
Stride is a positive number it is: 1280.
Also I have access to 'finally' because it is a MS extension to C++.
[Note: Code is updated because I pasted the wrong code in by mistake]
std::string GdiBitmapToBase64(Gdiplus::Bitmap* gdiBitmap, int width, int height)
{
unsigned char* charPixels = nullptr;
try
{
Gdiplus::Rect rect = Gdiplus::Rect(0, 0, width, height);
Gdiplus::BitmapData gdiBitmapData;
gdiBitmap->LockBits(&rect, Gdiplus::ImageLockMode::ImageLockModeRead, PixelFormat32bppARGB, &gdiBitmapData);
auto stride = gdiBitmapData.Stride;
if (stride < 0) stride = -stride;
charPixels = new unsigned char[height * stride];
memset(charPixels, 0, height * stride);
memcpy(charPixels, gdiBitmapData.Scan0, stride);
std::string ret = base64_encode(charPixels, stride);
gdiBitmap->UnlockBits(&gdiBitmapData);
return ret;
}
finally
{
if(charPixels != nullptr)
{
delete[] charPixels;
}
}
}
Here is the code which calls this method. This may help:
void CLIScumm::Wrapper::ScreenUpdated(const void* buf, int pitch, int x, int y, int w, int h, PalletteColor* color)
{
const unsigned char* bufCounter = static_cast<const unsigned char*>(buf);
for (int hightCounter = 0; hightCounter < h; hightCounter++, bufCounter = bufCounter + pitch)
{
for (int widthCounter = 0; widthCounter < w; widthCounter++)
{
PalletteColor currentColor = *(color + *(bufCounter + widthCounter));
gdiBitmap->SetPixel(x + widthCounter, y + hightCounter, Gdiplus::Color(currentColor.r, currentColor.g, currentColor.b));
}
}
_screenUpdated->Invoke(gcnew System::String(GdiBitmapToBase64(gdiBitmap, DISPLAY_DEFAULT_WIDTH, DISPLAY_DEFAULT_HEIGHT).c_str()));
}
And the declarations:
namespace CLIScumm {
public ref class Wrapper {
...
private:
...
Gdiplus::Graphics* gdiGraphics;
Gdiplus::Bitmap* gdiBitmap;
...
};
And the initialization:
void CLIScumm::Wrapper::init()
{
if (!hasStarted)
{
try
{
if (!hasStarted)
{
...
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
(malloc(sizeof(100000) * DISPLAY_DEFAULT_HEIGHT * DISPLAY_DEFAULT_WIDTH));
gdiBitmap = new Gdiplus::Bitmap(DISPLAY_DEFAULT_WIDTH, DISPLAY_DEFAULT_HEIGHT, PixelFormat32bppARGB);
gdiGraphics = new Gdiplus::Graphics(gdiBitmap);
InitImage();
...
}
}
...
}
}
Thank you all for you help, but I solved my own problem.
I was confusing bitmap pixel data with the actual bytes of a bitmap, and Scan0 is the former. The reason I was getting only zero's is because the first few frames were black.
I followed the example from C++ gdi::Bitmap to PNG Image in memory to get the actual bitmap bytes.
I modified the example function to:
bool SavePngMemory(Gdiplus::Bitmap* gdiBitmap, std::vector<BYTE>& data)
{
//write to IStream
IStream* istream = nullptr;
CreateStreamOnHGlobal(NULL, TRUE, &istream);
CLSID clsid_bmp;
CLSIDFromString(L"{557cf400-1a04-11d3-9a73-0000f81ef32e}", &clsid_bmp);
Gdiplus::Status status = gdiBitmap->Save(istream, &clsid_bmp);
if (status != Gdiplus::Status::Ok)
return false;
//get memory handle associated with istream
HGLOBAL hg = NULL;
GetHGlobalFromStream(istream, &hg);
//copy IStream to buffer
int bufsize = GlobalSize(hg);
data.resize(bufsize);
//lock & unlock memory
LPVOID pimage = GlobalLock(hg);
memcpy(&data[0], pimage, bufsize);
GlobalUnlock(hg);
istream->Release();
return true;
}
I was then able to convert data to base64 by calling:
base64_encode(&data[0], data.size());
I can't vouch for the quality of the code, because I don't understand how everything works.
I want to unlock a locked ID2D1Bitmap I have tried m_pBitmap1->Release(); but it doesn't seem to work
hr=m_pBitmap1->CopyFromRenderTarget(nullptr, m_pRenderTarget2, nullptr); gives an access violation error:
"Unhandled exception at 0x00fb2a46 in dent_detection_sys.exe: 0xC0000005: Access violation reading location 0x00000024."
WICRect rcLock = { 0, 0, sc_bitmapWidth , sc_bitmapHeight };
IWICBitmapLock *pILock=NULL;
hr =pWICBitmap->Lock(&rcLock, WICBitmapLockWrite, &pILock);
hr=pRT->CreateSharedBitmap(
IID_IWICBitmapLock,
static_cast<void *>(pILock),
&bp2,
&m_pBitmap1
);
hr=m_pBitmap1->Release();
hr=m_pBitmap1->CopyFromRenderTarget(nullptr, m_pRenderTarget2, nullptr);
To unlock the WIC bitmap, release the IWICBitmapLock:
pILock->Release();
You should only release m_pBitmap1 when you don't want to use it anymore.
hr=m_pBitmap1->CopyFromRenderTarget(nullptr, m_pRenderTarget2, nullptr);
hr=m_pBitmap1->Release();
According to the MSDN to use a shared WIC bitmap the render target type must be D2D1_RENDER_TARGET_TYPE_SOFTWARE when the render target is created.
cdemo is a structure object with basic d2d, wic, dwrite interface pointers.
example: cdemo->d2d.factory->CreateSomething(), cdemo->wic.factory->CreateSomething(), cdemo->dwrite.factory->CreateSomething, cdemo->xaudio.factory->CreateSomething, etc.
cbmp is a pointer to a structure that has interfaces and properties related to a WIC bitmap
The following example does not work as is without some tweaks and typo fixes, but it can be used to demonstrate how to use wic for editing a bitmap and directly accessing pixels
This code assumes that the cdemo->d2d.factory and cdemo->wic.factory are already created.
#define DEBUG_FAILED_GOTO(a,b) MessageBox(m_hwnd, a, L"FAILED", MB_OK); goto b
#define DEBUG_DISPLAY(a) MessageBox(m_hwnd, a, L"DEBUG", MB_OK)
#define USING_SHARED_WIC_BITMAP
#define USING_WIC_RENDER_TARGET
#define USING_WICBMP_COPY_TO_D2DBMP
struct COMMON_WIC_BGRA { BYTE b, g, r, a };
struct COMMON_WIC_BMP
{
//// Miscelaneous variables
bool ready;
bool using_d2d_bmp;
bool using_shared_bmp;
bool using_render_tgt;
bool ready_d2d_bmp;
bool ready_shared_bmp;
bool ready_render_tgt;
UINT BPPPP; // Bit-Per-Pixel-Per-Plane
UINT stride; // cbStride = row size;
UINT buff_size; // (org_size.y * stride);
POINT org_size, clip_TpLt, padding;
POINT cur_size, clip_BtRt;
D2D1_BITMAP_PROPERTIES props_bmp; // = D2D1::BitmapProperties();
D2D1_RENDER_TARGET_PROPERTIES props_tgt; // = D2D1::RenderTargetProperties();
WICPixelFormatGUID formatGUID; // = GUID_WICPixelFormat32bppPBGRA;
WICRect rc_lock; // the lock region, usually the entire
//// Interfaces
IWICBitmap* ifc_bmp; // WIC bitmap: lock and unlock bmp data;
IWICBitmapLock* ifc_lock; // Used to access the pixels to read/write
ID2D1RenderTarget* ifc_render_tgt; // Creates a d2d render target
ID2D1Bitmap* ifc_d2d_bmp; // creates an d2d bitmap for display
ID2D1Bitmap* ifc_shared_bmp; // creates a shared bitmap for display
ID2D1SolidColorBrush* ifc_render_brush; // This is needed for the render target
//// Data pointers
BYTE* byte; // Points to a pixel's byte; 8 bits
COMMON_WIC_BGRA* wpixel; // Points to a pixel; 32 bits
};
BOOL Lock_Release (COMON_WIC_BMP *cbmp);
BOOL Lock_Start (COMMON_INTERFACE_STUFF *cdemo, COMMON_WIC_BMP *cbmp, DWORD flags);
void Create_BMP_n_Stuff (
COMMON_INTERFACE_STUFF *cdemo,
COMMON_WIC_BMP *cbmp,
int org_xsize,
int org_ysize)
{
DEBUG_DISPLAY(L"Gate 0-1 Open: started xxx process");
if (cbmp == NULL) { return E_FAIL; }
if (cdemo == NULL) { return E_FAIL; }
DEBUG_DISPLAY(L"Gate 0-2 Open: passed the sanity test");
HRESULT hr = S_OK;
ZeroMemory(cbmp, sizeof(COMMON_WIC_BMP));
// Create a Direct2D render target.
if (cdemo->d2d.hwnd_tgt == NULL)
{
RECT rc;
GetClientRect(m_hwnd, &rc);
D2D1_SIZE_U size = D2D1::SizeU((rc.right - rc.left), (rc.bottom - rc.top));
cdemo->d2d.props_tgt = D2D1::HwndRenderTargetProperties(m_hwnd, size);
cdemo->d2d.props_tgt_type = D2D1_RENDER_TARGET_TYPE_SOFTWARE;
cdemo->d2d.props_bmp = D2D1::BitmapProperties();
hr = cdemo->d2d.factory->CreateHwndRenderTarget(
cdemo->d2d.props_tgt_type,
cdemo->d2d.props_tgt,
&cdemo->d2d.hwnd_tgt);
if (FAILED(hr)) { goto CleanUp; }
}
DEBUG_DISPLAY(L"Gate 1 Open: hwnd_tgt created");
cbmp->ready = false; // type is: bool
// this option is compatible to D2D bitmap without conversion
cbmp->formatGUID = GUID_WICPixelFormat32bppPBGRA; // type is: WICPixelFormatGUID
cbmp->buff_size = 0; // type is: UINT32
cbmp->stride = 0; // type is: UINT32
cbmp->clip_TpLt.x = 0; // type is: POINT or POINTS
cbmp->clip_TpLt.y = 0;
cbmp->clip_BtRt.x = cbmp->org_size.x = org_xsize; // type is: POINT or POINTS
cbmp->clip_BtRt.y = cbmp->org_size.y = org_ysize;
cbmp->byte = NULL; // type is: pointer to BYTE, BYTE*
cbmp->pixel = NULL; // type is: pointer to COMMON_WIC_BGRA, COMMON_WIC_BGRA*
cbmp->ifc_bmp = NULL; // type is: IWICBitmap*
cbmp->ifc_d2d_bmp = NULL; // type is: ID2D1Bitmap*
cbmp->ifc_lock = NULL; // type is: IWICBitmapLock*
cbmp->ifc_shared_bmp = NULL; // type is: ID2D1Bitmap*
cbmp->ifc_render_tgt = NULL; // type is: ID2D1RenderTarget*
cbmp->ifc_render_brush = NULL; // type is: ID2D1SolidColorBrush*
//D2D1_BITMAP_PROPERTIES props_bmp; = D2D1::BitmapProperties();
//D2D1_RENDER_TARGET_PROPERTIES props_tgt; = D2D1::RenderTargetProperties();
//bool ready;
//bool using_d2d_bmp;
//bool using_shared_bmp;
//bool using_render_tgt;
//bool ready_d2d_bmp;
//bool ready_shared_bmp;
//bool ready_render_tgt;
//UINT BPPPP; // Bit-Per-Pixel-Per-Plane
if (cdemo->wic.factory == NULL)
{ // (re)create the WIC factory
hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void **>(&cdemo->wic.factory));
if (FAILED(hr)) { goto CleanUp; }
}
hr = cdemo->wic.factory->CreateBitmap(
cbmp->org_size.x,
cbmp->org_size.y,
cbmp->formatGUID,
WICBitmapCacheOnDemand,
&cbmp->ifc_bmp);
// Experimental debug
//if (FAILED(hr)) { DEBUG_FAILED_GOTO(L"FAILED creating wic bitmap", CleanUp); }
if (FAILED(hr)) { goto CleanUp; }
DEBUG_DISPLAY(L"Gate 2 Open: created the WIC bitmap");
// type is: WICRect;
cbmp->rc_lock = { 0, 0, (UINT)cbmp->org_size.x, (UINT)cbmp->org_size.y };
hr = cbmp->ifc_bmp->Lock(&cbmp->rc_lock, WICBitmapLockWrite, &cbmp->ifc_lock);
hr = cbmp->ifc_lock->GetStride(&cbmp->stride); //row size = (xsize*BPPP) + xpadding
hr = cbmp->ifc_lock->GetDataPointer(&cbmp->buff_size, &cbmp->byte);
cbmp->wpixel = (COMMON_WIC_BRGA *)cbmp->byte;
// clear the bitmap
ZeroMemory(cbmp->byte, cbmp->buff_size);
#ifdef USING_SHARED_WIC_BITMAP
cbmp->props_bmp = D2D1:BitmapProperties();
hr = demo->d2d.hwnd_tgt->CreateSharedBitmap(
IID_IWICBitmapLock,
(void*)cbmp->ifc_lock,
&cbmp->props_bmp,
&cbmp->ifc_shared_bmp);
if (SUCCEDED(hr))
{
cbmp->using_shared_bmp = true;
DEBUG_DISPLAY(L"Gate 4-1 Open: created shared wic bitmap");
}
#endif
#ifdef USING_WICBMP_COPY_TO_D2DBMP
hr = cdemo->d2d.factory->CreateBitmapFromWicBitmap(
cbmp->ifc_bmp,
&cbmp->props_bmp,
&cbmp->ifc_d2d_bmp);
if (SUCCEDED(hr))
{
cbmp->using_d2d_bmp = true;
DEBUG_DISPLAY(L"Gate 4-2 Open: created d2d bitmap ");
}
#endif
#ifdef USING_WIC_RENDER_TARGET
cbmp->props_tgt = D2D1::RenderTargetProperties();
cbmp->props_tgt.type = D2D1_RENDER_TARGET_TYPE_SOFTWARE;
hr = cdemo->d2d.factory->CreateWicBitmapRenderTarget(
cbmp->ifc_bmp,
&cbmp->props_tgt,
&cbmp->ifc_render_tgt);
if (SUCCEDED(hr))
{
hr = cbmp->ifc_render_tgt->CreateSolidColorBrush(
{ 1.0f, 1.0f, 1.0f, 1.0f }, // Solid white
&cbmp->ifc_render_brush);
cbmp->using_shared_bmp = true;
DEBUG_DISPLAY(L"Gate 4-3 Open: created wic render target and brush");
}
#endif
if (FAILED(hr)) { goto CleanUp; }
cbmp->ready = true;
// Rules of engagement if using all possible combinations above
// 1) After SafeRelease(&cbmp->ifc_lock) you cannot use cbmp->byte or cbmp->wpixel
// 2) To use cbmp->ifc_render_tgt you must first SafeRelease(cbmp->ifc_lock) and
// SafeRelease(&cbmp->ifc_shared_bmp). Later reinitialize them as needed.
// 3) To display the wic bitmap (cbmp->ifc_bmp) onto cdemo->d2d.hwnd_tgt:
// you cannot copy the wic bitmap (cbmp->ifc_bmp) directly to an hwnd render target
// option 1: This is whole point of creating the shared bmp
// cdemo->d2d.hwnd_tgt->DrawBMP( [ &dst_rc, ] cbmp->ifc_shared_bmp);
// option 2: Copy the pixels to the d2d bitmap, copy the d2d bitmap to the target
// cbmp->ifc_d2d_bmp->CopyFromMemory(cbmp->byte, &dst_rc, cbmp->stride);
// cdemo->d2d.hwnd_tgt->DrawBMP( [ &dst_rc, ] cbmp->ifc_d2d_bmp);
// option 3: Copy from the render target to the d2d bitmap
// cbmp->ifc_d2d_bmp->CopyFromRenderTarget(&pt_dst, cbmp->ifc_render_tgt, &src_rc);
// cdemo->d2d.hwnd_tgt->DrawBMP( [ &dst_rc, ] cbmp->ifc_d2d_bmp);
// 4) When drawing directly to the wic bitmap either use cbmp->ifc_render_tgt or
// cbmp->ifc_lock + cbmp->byte + your own algorithms to draw shapes
//
// 5) for simplicty: it can get confusing when trying to use all methods
option 1: use the ifc_lock with the ifc_shared_bmp + your own algorithms
option 2: use the ifc_render_tgt with the ifc_d2d_bmp
// Example: Draw a filled 12x15 rectangle example:
int x = 20, byte_col = 0, wpixel_col = 0, sizey = 12;
int y = 35, byte_row = 0, wpixel_row = 0, sizex = 15;
D2D1_COLOR_F d2d_colr = { 0.50f, 0.10f, 0.80f, 1.00f }; //some random color
COMMON_WIC_BGRA wic_colr = { 0, 0, 0, 0 };
D2D1_POINT_2U d2d_pt_dst_f = { 0, 0 };
D2D_RECT_F d2d_outputrect = { 0.0f, 0.0f, 0.0f, 0.0f };
D2D1_RECT_F d2d_dst_rcf =
{ 0.0f, 0.0f, (FLOAT)cbmp->org_size.x, (FLOAT)cbmp->org_size.y };
D2D1_RECT_U d2d_src_rcu =
{ 0, 0, (UINT32)cbmp->org_size.x, (UINT32)cbmp->org_size.y };
WIC_RECT_U wic_dst_rcu =
{ 0, 0, (UINT32)cbmp->org_size.x, (UINT32)cbmp->org_size.y };
WIC_RECT_U wic_src_rcu = wic_dst_rcu
// must release the lock and shared bitmap before using the render target
Lock_End(cbmp);
// This should look familiar
d2d_outputrect = { (FLOAT)x, (FLOAT)y, (FLOAT)(x+sizex-1), (FLOAT)(y+sizey-1) };
cbmp->ifc_render_tgt->BeginDraw();
cbmp->ifc_render_brush->SetColor(d2d_colr);
cbmp->ifc_render_tgt->SetTransform(D2D1::IdentityMatrix());
cbmp->ifc_render_tgt->FillRectangle(&d2d_outputrect, cbmp->ifc_render_brush);
hr = cbmp->ifc_render_tgt->EndDraw();
// display the wic bitmap on the hwnd render target
hr = cbmp->ifc_d2d_bmp->CopyFromRenderTarget(
&d2d_pt_dst,
cbmp->ifc_render_tgt,
&d2d_src_rc);
hr = cdemo->d2d.hwnd_tgt->DrawBMP(&d2d_dst_rc, cbmp->ifc_d2d_bmp);
// Alternative: using the ifc_lock with the ifc_shared_bmp + home grown algorithms
if (!Lock_Start(cdemo, cbmp, WICBitmapLockWrite)) { goto CleanUp; }
// convert D2D1_COLOR_F { b, g, r, a} to BYTE { b, g, r, a }
wic_colr.b = (BYTE)ceil(d2d_colr.b * 255);
wic_colr.g = (BYTE)ceil(d2d_colr.g * 255);
wic_colr.r = (BYTE)ceil(d2d_colr.r * 255);
wic_colr.a = (BYTE)ceil(d2d_colr.a * 255);
for (int run_y = 0; run_y < sizey; ++run_y)
{
// clipping for the y values
if (((run_y + y) < cbmp->clip_TpLt.y) || ((run_y + y) >= clip_BtRt.y))
{ continue; }
// convert the y to a byte position
byte_row = ((run_y + y) * cbmp->stride);
wpixel_row = ((run_y + y) * cbmp->org_size.x) + cbmp->padding.x; //optional
for (int run_x = 0; run_x < sizex; ++run_x)
{
// clipping for the x values
if (((run_x + x) < cbmp->clip_TpLt.x) || ((run_x + x) >= clip_BtRt.x))
{ continue; }
// convert the x to an offset position
byte_col = ((run_x + x) * 4); // must multiply by 4 bytes (b, g, r, a)
wpixel_col = (run_x + x); // cbmp->wpixel points to every 4 bytes
// access the pixels by means of pointer[(y_position + x_offset)]
cbmp->byte[(byte_row + byte_col + 0)] = wic_colr.b;
cbmp->byte[(byte_row + byte_col + 1)] = wic_colr.g;
cbmp->byte[(byte_row + byte_col + 2)] = wic_colr.r;
cbmp->byte[(byte_row + byte_col + 3)] = wic_colr.a;
cbmp->wpixel[(wpixel_row + wpixel_col)] = wic_colr; // Alternative
// Another method
cbmp->wpixel[(wpixel_row + wpixel_col)].b = wic_colr.b; // Alternatives
cbmp->wpixel[(wpixel_row + wpixel_col)].g = wic_colr.g; // Alternatives
cbmp->wpixel[(wpixel_row + wpixel_col)].r = wic_colr.r; // Alternatives
cbmp->wpixel[(wpixel_row + wpixel_col)].a = wic_colr.a; // Alternatives
}
}
// display the wic bitmap on the hwnd render target
cdemo->d2d.hwnd_tgt->DrawBMP(&dst_rc, cbmp->ifc_shared_bmp);
// Optionally release the lock after every use
// Lock_Release(cbmp);
return; // commnent out if cleanup is required
CleanUp:
// SafeRelease everything that needs to be released
}
BOOL Lock_Start (
COMMON_INTERFACE_STUFF *cdemo,
COMMON_WIC_BMP *cbmp,
DWORD flags)
{
if (cdemo == NULL) { return FALSE; }
//if (!cdemo->ready) { CreateResouces(cdemo); }
if (cbmp == NULL) { return FALSE; }
if (cbmp->ifc_lock != NULL) { return TRUE; }
SafeRelease(&cbmp->ifc_lock);
hr = cbmp->ifc_bmp->Lock(&cbmp->rc_lock, flags, &cbmp->ifc_lock);
if (FAILED(hr)) { return FALSE; }
hr = cbmp->ifc_lock->GetStride(&cbmp->stride);
hr = cbmp->ifc_lock->GetDataPointer(&cbmp->buff_size, &cbmp->byte);
cbmp->wpixel = (COMMON_WIC_BGRA *)cbmp->byte;
// recreate the shared bitmap
SafeRelease(&cbmp->ifc_shared_bmp);
hr = cdemo->d2d.factory->CreateSharedBitmap(
IID_IWICBitmapLock,
(void*)cbmp->ifc_lock,
&cbmp->props_bmp,
&cbmp->ifc_shared_bmp);
return TRUE;
}
BOOL Lock_Release (COMON_WIC_BMP *cbmp)
{
if (cbmp == NULL) { return FALSE; }
if (cbmp->ifc_lock == NULL) { return TRUE; }
SafeRelease(&cbmp->ifc_lock);
SafeRelease(&cbmp->ifc_shared_bmp);
cbmp->byte = NULL;
cbmp->wpixel = NULL;
if (cbmp->using_render_tgt) { cbmp->ready_render_tgt = true; }
return TRUE;
}
Recently, I've found a bug in my 3D application that uses DirectX 9. The bug is that everytime I alt-tab or ctrl-alt-delete, the program freezes or seems to do nothing. I've looked around and found out that I need to reset my device by using IDirect3DDevice9::TestCooperativeLevel and IDirect3DDevice9::Reset. But what I'm struggling on at the moment is that (as far as I know) before I Reset the device, I need to release the resouce in D3DPOOL_MANAGE before I reset the device and reallocate the resource back to it after the Reset? How do I do this? Below is the code I've got for the reset of my device (in the IsDeviceLost() function).
DirectX.h
#pragma once
#pragma comment(lib, "d3d9.lib")
#include<d3d9.h>
#include<d3dx9math.h>
#include"Window.h"
#include"Vertex.h"
#include"Shader.h"
#define VERTEXFORMAT (D3DFVF_XYZ | D3DFVF_TEX1) //Flags for the Flexible Vertex Format (FVF)
class Shader;
class DirectX
{
public:
DirectX(std::string windowTitle, int x, int y, unsigned int windowWidth, unsigned int windowHeight, bool fullscreen);
virtual ~DirectX();
static LPDIRECT3D9 direct3D;
static LPDIRECT3DDEVICE9 device;
static IDirect3DVertexDeclaration9* vertexDec;
static ID3DXEffect* currentShaderEffect;
void CheckShaderVersion();
bool IsDeviceLost();
protected:
D3DPRESENT_PARAMETERS direct3DPresPara;
Window *window;
unsigned int width;
unsigned int height;
D3DXMATRIX projMatrix;
private:
void Initialize(bool fullscreenMode);
};
Direct.cpp
#include"DirectX.h"
LPDIRECT3D9 DirectX::direct3D = NULL;
LPDIRECT3DDEVICE9 DirectX::device = NULL;
IDirect3DVertexDeclaration9* DirectX::vertexDec = NULL;
ID3DXEffect* DirectX::currentShaderEffect = NULL;
DirectX::DirectX(std::string windowTitle, int x, int y, unsigned int windowWidth, unsigned int windowHeight, bool fullscreen)
{
width = windowWidth;
height = windowHeight;
window = new Window(windowTitle.c_str(), windowWidth, windowHeight, x, y, fullscreen);
Initialize(fullscreen);
D3DXMatrixPerspectiveFovLH( &projMatrix,
D3DXToRadian(45),
(float)width/(float)height,
1.0f,
15000.0f);
//device->SetTransform(D3DTS_PROJECTION, &projMatrix);
}
DirectX::~DirectX()
{
direct3D->Release();
device->Release();
vertexDec->Release();
delete vertexDec;
delete currentShaderEffect;
delete window;
}
void DirectX::Initialize(bool fullscreenMode)
{
direct3D = Direct3DCreate9(D3D_SDK_VERSION);
ZeroMemory(&direct3DPresPara, sizeof(direct3DPresPara));
switch(fullscreenMode)
{
case true:
direct3DPresPara.Windowed = false;
break;
case false:
direct3DPresPara.Windowed = true;
}
direct3DPresPara.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; //turns off VSync, comment this line of code to turn VSync back on
direct3DPresPara.SwapEffect = D3DSWAPEFFECT_DISCARD;
direct3DPresPara.hDeviceWindow = window->GetHandle();
direct3DPresPara.BackBufferFormat = D3DFMT_X8R8G8B8;
direct3DPresPara.BackBufferWidth = width;
direct3DPresPara.BackBufferHeight = height;
direct3DPresPara.EnableAutoDepthStencil = TRUE;
direct3DPresPara.AutoDepthStencilFormat = D3DFMT_D16;
direct3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window->GetHandle(), D3DCREATE_SOFTWARE_VERTEXPROCESSING, &direct3DPresPara, &device);
D3DVERTEXELEMENT9 vertexElement[] = { {0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
D3DDECL_END()};
device->CreateVertexDeclaration(vertexElement, &vertexDec);
//currentShaderEffect = 0;
}
void DirectX::CheckShaderVersion()
{
D3DCAPS9 caps;
device->GetDeviceCaps(&caps);
bool stop = false;
int i = 6;
while(!stop)
{
if(caps.VertexShaderVersion < D3DVS_VERSION(i, 0))
{
i--;
}
else
{
std::cout << "you are using shader model " << i << std::endl;
stop = true;
}
}
//std::cout << caps.VertexShaderVersion << std::endl;
//std::cout << D3DVS_VERSION(3, 0) << std::endl;
}
bool DirectX::IsDeviceLost()
{
HRESULT result = device->TestCooperativeLevel();
if(result == D3DERR_DEVICELOST)
{
Sleep(20); //Sleep for a little bit then try again.
return true;
}
else if(result == D3DERR_DRIVERINTERNALERROR)
{
MessageBox(0, "Internal Driver Error. The program will now exit.", 0, 0);
PostQuitMessage(0);
return true;
}
else if(result == D3DERR_DEVICENOTRESET)
{
device->Reset(&direct3DPresPara);
return false;
}
else
{
return false;
}
}
Any help or advice will be greatly appreciated. Thanks
You don't need to release resources in D3DPOOL_MANAGED. You need to release resources in D3DPOOL_DEFAULT.
If you're using D3DX objects (ID3DXFont, ID3DXMesh, ID3DXSprite), they typically have "OnLostDevice" and "OnResetDevice" methods. You should call those methods in appropriate situations.
If an object does not have any methods for dealing with "DeviceLost" state, and they should be released, simply destroy the object before resetting the device, and reload it afterwards.
Please note that D3DPOOL_MANAGED objects are reloaded automatically by the driver and don't need any "help" from you to deal with reset/devicelost. YOu do need to take care about all other objects.
In addition to what I said/wrote, you should obviously read DirectX SDK documentation. They cover lost devices in their documentation, and DirectX examples normally survive device reset just fine.