Quick question guys... I am currently working with Directx3D and 2D and I was wondering if I have to recreate the render target when the Windows is resized or does Direct2D automatically detects this, since it's bound to the DXGISurface(back-buffer of the swapchain) when I created it.
Here is the code that I used to bind the render targets together:
ComPtr<IDXGISurface1> dxgibackBuffer;
hr = m_pDxSwapchain->GetBuffer(0, IID_PPV_ARGS(&dxgibackBuffer));
D2D1_BITMAP_PROPERTIES1 bitmapProperties = D2D1::BitmapProperties1(
D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE),
96.0f,
96.0f);
hr = m_pD2DContext->CreateBitmapFromDxgiSurface(dxgibackBuffer.Get(), &bitmapProperties, &m_pD2DTargetBitmap);
// last step
m_pD2DContext->SetTarget(m_pD2DTargetBitmap.Get());
See Care_and_Feeding_of_the_Swap_Chain and Handling_Window_Resizing
Quote1:
Naturally, the application's best route is to respond to WM_SIZE, and call IDXGISwapChain::ResizeBuffers, passing the size contained in the message's parameters.
Quote2:
Before you call ResizeBuffers, you must release all outstanding references to the swap chain's buffers. The object that typically holds a reference to a swap chain's buffer is a render-target-view.
Related
I'm using MFC...
When I create a new brush, I know I need to restore the old bush using SelectObject:
CBrush brushFill;
brushFill.CreateSolidBrush(colorFill);
CBrush *oldBrush = pDC->SelectObject(&brushFill);
// Draw something here.
pDC->SelectObject(oldBrush);
However, if I get the brush using GetStockObject(), do I need to to restore it, too?
CBrush *oldBrush = (CBrush *)pDC->SelectObject(GetStockObject(HOLLOW_BRUSH));
// Draw something here.
pDC->SelectObject(oldBrush);
I ask, because that code occasionally crashes. I'm unsure if that's due to me not supposed to save/restore stock items, or my typecast to a CBrush*. If the latter, I'm thinking I should save/restore an HGDIOBJ handle:
HGDIOBJ oldBrush = pDC->SelectObject(GetStockObject(HOLLOW_BRUSH));
// Draw something here.
pDC->SelectObject(oldBrush);
If the former, I wouldn't save/restore the previous object.
You should always 'bracket' any operations on a device context with the SaveDC() and RestoreDC() member functions of the CDC object:
int DCsave = pDC->SaveDC(); // Saves all (or most) settings and object selections
// ... Do your drawing operations, etc.
pDC->RestoreDC(DCsave); // Restores the saved state and all selected objects
Also, just for info, you may find the SelectStockObject() member a bit easier to use:
pDC->SelectStockObject(HOLLOW_BRUSH);
Note (from the comment made by IInspectable): Although deselection of the GDI 'Stock Objects' may seem unnecessary (after all, there will be several of these selected by default), other code may be relying on having the previous object (brush, in your case) selected; failure to restore this selection can thus cause that code to fail in ways that are near impossible to track down.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
Is wglMakeCurrent supposed to be called only once or does it need to be called before every buffer swap?
Can current opengl context be reset by some external thing other then setting it via wglMakeCurrent?
I am here just to narrow the possible problem. I can't post relevant code here because I have no idea which part is relevant.
Currently I have loop that does makeCurrent -> clear -> render. It renders correctly. I tried make context current on initialization without making it current every draw, but it rendered empty screen. Only when I exited window the correct render flickered for one frame. I figured that something is wrong by using nvidia's graphics debugger. The debugger's overlay strangelly flickered. It doesn't do that with other applications.
Is wglMakeCurrent supposed to be called only once
Each GL context can be made current to at most one thread and drawable at every single point in time. If you only use one Window and one GL Context, it is enough to call wglMakeCurrent only once after you created the context and the window.
If you use one context for multiple windows, you have to re-bind it at least once per frame and window. Note that switching the current context or window traditionally implied flushing the GL pipeline, but this can nowadays be prevented via the KHR_context_flush_control extension, making such a scheme much more efficient.
If you use multiple threads but a single GL context, you must push around the context from thread to thread by making it uncurrent in some thread, and making it current again in the new thread, and so on. But that scheme should almost never be necessary. Fur mutli-threaded GL, you should create mutlipe shared contexts, and then, you usually need one wglMakeCurrent per thread.
or does it need to be called before every buffer swap?
Note that the SwapBuffers function is not a GL function (hence also no gl prefix in the name), and therefore, does work independently of the currently active GL context - the function takes the HDC of the window you want the buffer swap to occur.
Can current opengl context be reset by some external thing other then setting it via wglMakeCurrent?
No, not really. There is the graphics reset situation which can be handled via ARB_robustness:
* Provide a mechanism for an OpenGL application to learn about
graphics resets that affect the context. When a graphics reset
occurs, the OpenGL context becomes unusable and the application
must create a new context to continue operation. Detecting a
graphics reset happens through an inexpensive query.
But such a _graphics reset does not unbind the current GL context - the affected context is just not usable any more.
Win32:
With a Tree Control created and the style changed to TVS_CHECKBOXES and then the ImageList for the TVSIL_STATE changed to a custom ImageList, do you need to delete the returned prior ImageList or is it a shared resource and should not be.
MFC:
Since there is an object hierarchy, in this case you don't know if the CImageList is replacing a one provided by the system or from one of the parent classes. In that case what is the proper handling? For ImageLists, can you CImageList::Attach(), CTreeCtrl::SetImageList(), CImageList::Detach() then CTreeCtrl::OnDestroy() go ahead and CImageList *pil=CTreeCtrl::SetImageList(NULL, TVSIL_STATE) and then pil->DeleteImageList(), but then what about the object, are we supposed to delete pil instead? Or are we always required to setup a member variable that is the image list and just CTreeCtrl::SetImageList() to change it then OnDestroy() put back the old one or just set it to NULL?
Can changing ImageList used by TVS_CHECKBOXES cause resource leak?
Yes. From Tree-View Control Window Styles:
Destroying the tree-view control does not destroy the check box state
image list. You must destroy it explicitly. Get the handle to the
state image list by sending the tree-view control a TVM_GETIMAGELIST
message. Then destroy the image list with ImageList_Destroy.
Bonus "Old New Thing" link: Beware of the leaked image list when using the TVS_CHECKBOXES style
Win32 Solution
We can take advantage of the fact that TVM_SETIMAGELIST (wrapped by TreeView_SetImageList()) returns the handle to the previous image list.
HIMAGELIST hNewImageList = ImageList_Create(/* insert arguments */);
HIMAGELIST hOldImageList = TreeView_SetImageList( hwndTreeView, hNewImageList, TVSIL_STATE );
if( hOldImageList ) // a good habit, to check if handle is not NULL
{
ImageList_Destroy( hOldImageList );
hOldImageList = NULL;
}
After the tree control has been destroyed, you also have to ImageList_Destroy the new image list.
MFC Solution
MFC is not that much different, i. e. it doesn't automatically clean up the image list created by the TVS_CHECKBOXES style.
Create a member variable CImageList m_newImageList; in the declaration of the class that hosts the tree control (e. g. a CDialog derived class). This makes sure that the new image lists lifetime does not end before that of the tree control window and automatically destroys the image list through its destructor.
m_newImageList.Create(/* insert arguments */);
CImageList* pOldImageList = m_treeCtrl.SetImageList( &m_newImageList, TVSIL_STATE );
if( pOldImageList )
{
pOldImageList->DeleteImageList();
pOldImageList = nullptr;
}
CTreeCtrl::SetImageList() returns a pointer to a temporary object (via CImageList::FromHandle()) that does not own the handle it wraps. You have to DeleteImageList() to avoid the resource leak, but never delete on the pointer returned by SetImageList. MFC automatically cleans up temporary objects during idle processing (in CWinApp::OnIdle()).
Further reading:
TN003: Mapping of Windows Handles to Objects.
What is the lifetime of a CWnd obtained from CWnd::FromHandle?
(replace CWnd by CImageList, the FromHandle() methods of MFC classes all work in the same way).
The codes below is in winmain function after registering a class for the parent window:
RECT disrect;
HWND stat = CreateWindow("BUTTON","abcdef",
WS_CHILD|WS_VISIBLE|BS_OWNERDRAW,10,150,500,100,dis,0,0,0);
HDC hdc=GetDC (stat);
FillRect(hdc,&disrect,CreateSolidBrush(RGB(3,5,54)));
SetTextColor(hdc,RGB(25,250,250));
POINT p[3];
p[1].x=280;
p[1].y=280;
p[2].x=280;
p[2].y=290;
p[3].x=285;
p[3].y=285;
Polygon(hdc,p,3);
TextOut(hdc,10,10,"hhhhh",5);
But when I run it, only shows a white rectangle into the parent window, neither the rect is filled with black brush, nor there is any text in it.
Could you guys tell me where I am wrong?
Unless you want to display animations, you should never try to directly write to a window that way, because many events could cause the window to redraw itself erasing what you have just written.
The correct way is to put it in the WM_PAINT handler.
A few issues, in addition to not using WM_PAINT.
First, merely calling CreateSolidBrush() is not enough to mark that brush as the one for your drawing operations to use. You have to select the brush into a DC (device context) before you can use it. This is done with the SelectObject() function. General usage looks like
HBRUSH prevBrush;
prevBrush = SelectObject(hdc, newBrush);
// drawing functions
SelectObject(hdc, prevBrush);
Yes, it is important to restore the previous brush when finished, even on a fresh DC; the initial state must be restored. The initial state uses a brush that draws nothing; this is why your Polygon() doesn't draw anything. SelectObject() is used for all the various things you use to draw with (pens, fonts, etc.), not just brushes.
Second, in C array indices start at 0 and go to size - 1, not start at 1 and go to size. So instead of saying pt[1], pt[2], and pt[3], you say pt[0], pt[1], and pt[2]. Your compiler should have warned you about this.
Third, as the documentation for CreateSolidBrush() will have said, once you are finished with the brush you must destroy it with DeleteObject(). You must do this after selecting the previous brush back in. You must also do this with the brush you used in the FillRect() call.
This is a kind of GUI automation application whereby I want to read the data from a listview from another process.
The listview class is SysListView32 and has following styles set LVS_OWNERDRAWFIXED
Generally I am able to read the text from listview using the following procedure
Allocate memory in the memory space of other process
Send message to listview to read the text with the pointer of buffer allocated in that process
Read the buffer
It works fine when the listview is not ownerdrawn but in this case, the listview appears to be drawn by the owner, i.e. the listitem has no data.
Is it possible to read the text from such a listview either by the method I have discussed or by any method or by hooking the api or whatsoever method ?
The control must still add LVITEMs to the list view. But of course there's no obligation to put anything useful in them. Specifying a null pszText or iImage would work just fine if the app does its own drawing. It will implement a WM_DRAWITEM message handler and use internal data to render the item.
There is no way to find out where that data is stored. You could fake your own WM_DRAWITEM message, albeit that it is very hard to do since you must inject code to create the HDC, but that just gets you pixels, not bytes. Using OCR would be a major outlier solution. Realistically you'll need to throw in the towel on this one.