How update multiply descriptorSets at once - c++

I have multiply render targets from my swapchain and create a descriptorSet per target. The idea ist to create one commandBuffer per renderTarget und bind the equivalent descriptor. Now I want to update the descriptorSets with one single call of updateDescriptorSets and used:
std::vector<vk::WriteDescriptorSet> writes;
for( UINT32 index = 0; index < descriptorSets.size(); ++index )
{
writes.push_back(
vk::WriteDescriptorSet( descriptorSets[index], 0, 0, 1,
vk::DescriptorType::eStorageImage,
&vk::DescriptorImageInfo( vk::Sampler(), imageViews[index], vk::ImageLayout::eGeneral ),
nullptr,
nullptr ) );
}
device.updateDescriptorSets( writes.size(), writes.data(), 0, nullptr );
With this approach only the last renderTarget in the queue presents the wanted result. The others produce just black screens.
But when i call updateDescriptorSets multiply times all works like expected:
std::vector<vk::WriteDescriptorSet> writes;
for( UINT32 index = 0; index < descriptorSets.size(); ++index )
{
writes.push_back(
vk::WriteDescriptorSet( descriptorSets[index], 0, 0, 1,
vk::DescriptorType::eStorageImage,
&vk::DescriptorImageInfo( vk::Sampler(), imageViews[index], vk::ImageLayout::eGeneral ),
nullptr,
nullptr ) );
device.updateDescriptorSets( writes.size(), writes.data(), 0, nullptr );
writes.clear();
}
I thought that i can update multiply descriptorSets at once. So it is not possible or what else could be my error.
PS: I use the c++ Header frome the vulkan SDK

The Bug is indeed in the application code.
The problem lies in the creation of the vk::DescriptorImageInfo. In both code examples the struct only exits in the scope of the for-loop but than only a pointer to the struct is copied in the vk::WriteDescriptorSet struct.
When the updateDescriptorSets in the first example processes the data in the structs, the relevant data is out of scope and the pointers are invalid. Coincidentally the application uses always the same memory space in every iteration of the loop and so the pointers points to the same invalid space where the data of the last loop iteration still exits. This is why the last render target shows the expected result.

Related

Modifying set while iterating gives me segfault

I am currently working on a function working with a vector of sets of int.
I want my function merge( ) to merge all sets that share an int in common, so for example I want this to happen :
[0] - 0, 1, 2
[1] - 1, 3 Then it will [0] - 0, 1, 2, 3
[2] - 0, 3 output this vector -> [1] - 4, 5
[3] - 4, 5 [2] - 6, 7, 8, 9
[4] - 6, 7, 8
[5] - 8, 9
I have already written this function, of which code is presented down here.
I have commented almost every line so that it is not too difficult to understand my code !
// Merges all sets that shares at least one int
//
// PARAMETERS...
// vectorE : vector of sets of int
void mergeStates( std::vector< std::set< int > >& vectorE )
{
// For every set of ints
for( auto &currentSet : vectorE )
{
// For every ints of the set
for( auto currentInt : currentSet )
{
// The two for( ) loops down there allow me to iterate over
// every int of every set of the vectorE
for( auto setToCheck : vectorE )
{
// If the set is different from the one we're already targeting
if( currentSet != setToCheck )
{
for( auto intToCheck : setToCheck )
{
// if we have found an int that is the same as the one we're targeting
if( intToCheck == currentInt )
{
// Merge
etatsetEtudie.insert( setToCheck.begin(), setToCheck.end() );
// Deleting the set we copied from, because we won't need it anymore
for(auto setToErase = vectorE.begin() ; setToErase != vectorE.end() ; ){
if( *setToErase == setToCheck )
setToErase = vectorE.erase( setToErase );
else
++setToErase;
}
}
}
}
}
}
}
}
Every time I run my program, I get a segfault when it comes to deleting the set we copied from : where is my error?
Edit : I got it to work !
Alright, thanks guys I simply made my parameter const and added a return value so that I can add dynamically every constructed set I need to a new vector, and return this vector :-)
The problem isn't modifying any set, it's modifying the vector.
Erasing something from a vector shifts the elements after it. First, this means iterators into the vector after the erased position (the for-range loop uses iterators internally) are no longer valid. Second, if the shifting copied and overwrote sets (instead of moving them), all your iterators into the sets will no longer be valid.
The result is lots of undefined behavior in your code.
Also, your innermost loop is not a good way to go about erasing the set, even if the method was valid. It's very, very inefficient.
You need to rethink, at the very least, the way you're erasing elements. But I think that coming up with a generally better algorithm would be the better approach.
Try to make a new vector instead of modifying the original one:
std::vector<std::set<int>> mergeStates(const std::vector<std::set<int>> & vectorE ) {
std::vector<std::set<int>> new_vector;
...
return new_vector;
}
You are using the std::vector::erase function which invalidates iterators. Consequently your code inside the range based for loop tries to access the iterator past the container end.
The end iterator used by the range-based for is determined prior to the loop. Since you erase() during the iteration, the end actually changes. Obtaining the iterator from the result of the erase() is insufficient as the end also changed. I think you can get away not using range-based for loops for the ranges you erase from.

c++ Excel OLE automation. Setting the values of an entire cell-range 'at once'

IDE: Embarcadero XE5
I am attempting to improve the performance(speed) of an 'export to excel' procedure.
The procedure contains way too many OLE function calls and property read/write calls, hence the poor performance.
At present, a grid(2D array) is exported to excel by stepping through each cell in the grid and setting it's value.
I'm trying to export the entire grid into a excel cell-range at once, but failing in my attempts.
Now for Embarcadero Delphi-users this seems to be a trivial task:
// NOTE: This obviously won't compile, just showing the process.
var
arrData: Variant;
begin
// Create a 2D Variant array
arrData := VarArrayCreate([1, RowCount, 1, ColCount], varVariant);
// Fill array with values...
// Get a range of cells, size equal to arrData dimensions...
Range.Value := arrData; // Done, easy.
end;
For Embarcadero c++ -users however(or perhaps just myself), it doesn't seem to be all that obvious.
I've managed to create and fill a single-dimensional array with data, using:
VarArrayCreate, Embarcadero Example.
I tried to assign that array to a cell-range as follows:
Variant vArray;
// Create and fill vArray with data. Test case.
int bounds[2] = {0, 4};
// Creates Variant array containing 5 elements of type varVariant.
// Can set the element type to varInteger as well for this case, made no difference to the end result.
vArray = VarArrayCreate( bounds, 1, varVariant );
// Fill vArray with test data, values 0,1,2,3,4
for ( int index = 0; index < 5; index++ ) {
VarArrayPut( vArray, index, &index, 0 );
}
Variant vWorkSheet; // Active excel worksheet
Variant vCells = vWorkSheet.OlePropertyGet( L"Cells" );
Variant vRange; // A excel cell-range, equal in size to my vArray's size.
Variant vRange = vCells.OlePropertyGet( L"Range", vCells.OlePropertyGet(L"Item", 1, 1), vCells.OlePropertyGet(L"Item", 5, 1) );
vRange.OlePropertySet( L"Value", vArray ); // Similar to what is done in Delphi in example above.
...resulting in the entire excel cell-range being filled with the first value in vArray.
How would you go about creating multi-dimensional Variant arrays(two-dimensional in this case)?
How do you assign the Variant array to an Excel cell-range using OLE?
Creating a multi-dimensional Variant array is simply a matter of specifying more than 1 set of low/high bounds, just like the Delphi code showed:
Variant arrData = VarArrayCreate(OPENARRAY(int, (1, RowCount, 1, ColCount)), varVariant);
Or:
int bounds[4] = {1, RowCount, 1, ColCount};
Variant arrData = VarArrayCreate(EXISTINGARRAY(bounds), varVariant);
Then you can do this:
// Fill arrData with values...
// Get a range of cells, size equal to arrData dimensions...
Variant Range = ...;
Range.OlePropertySet(L"Value", arrData);
When you call VarArrayPut(), you specify an array of indexes, one for each dimension, to indicate the specific element that you want to assign the value to:
VarArrayPut( arrData, value, OPENARRAY(int, (indexDim1, indexDim2)) );
Or:
int indexes[2] = {indexDim1, indexDim2};
VarArrayPut( arrData, value, EXISTINGARRAY(indexes) );

Grouping 2D array of instances

I have a working solution for this, though I am convinced there must be a better implementation. In a nut shell the problem is this:
I am working on a connect>=3, bejewelled style puzzle game. When the state of the 'board' changes I group all the pieces such that if they are 'connected' horizontally or vertically they share an ID. This is how I do it currently:
[pseudo]
for all( array object* )
{
if !in_a_group() check_neighbours( this )
}
void check_neighbours( ID )
{
if ( check_is_same_type( left ) )
{
if !in_a_group() this.ID = ID ; check_neighbours( ID )
else if( in_a_group ) change_IDs(this.ID, ID )
}
same for right ...
up ...
down ...
}
That is a really dirty pseudo version of what I do.
I recursively call check_neighbours, passing the ID of the first branch piece forward (I use this pointer as an ID rather than generating one).
If I find a piece with a different ID that is connected I overwrite all pieces with that ID with new ID ( I have an ASSERT here cos it shouldn't actually happen. It hasn't so far in lots of testing)
I don't check_neighbours at the original branch unless the piece has no ID.
This works just fine, though my pseudo is probably missing some small logic.
My problem is that it has the potential to use many branches (which may be a problem on the hardware I am working on). I have worked on the problem so long now that I can't see another solution. Ever get the feeling you are missing something incredibly obvious?
Also I am new to stackoverflow, reasonably new to programming and any advice on etiquette etc is appreciated.
How would you suggest avoiding recursion?
As I understand it, your algorithm is basically a "flood fill" with a small twist.
Anyway, to avoid recursion, you need to allocate array to store coordinates of unprocessed items and use queue or fifo. Because you know dimensions of grid (and since it is bejeweled-style(?) game, you should be able to preallocate it pretty much anywhere.
pseudocode for any flood-fill-type recursive algorithm.
struct Coord{
int x, y;
}
typedef std::queue<Coord> CoordQueue;
bool validCoord(Coord coord){
return (coord.x >= 0) && (coord.y >= 0)
&& (coord.x < boardSizeX) && (coord.y < boardSizeY);
}
bool mustProcessCoord(Coord coord);
void processAll(){
CoordQueue coordQueue;
Coord startPoint = Coord(0, 0);
coordQueue.pushBack(startPoint);
while (!coordQueue.empty()){
const Coord &curCoord = coordQueue.front();
//do something with current coordinates.
processCoord(curCoord);
const int numOffsets = 4;
const int offsets[numOffsets][2] = {{-1, 0}, {0, -1}, {1, 0}, {0, 1}};
for (int offsetIndex = 0; offsetIndex < numOffsets; offsetIndex++){
Coord neighborCoord = Coord(curCoord.x + offsets[offsetIndex][0],
curCoord.y + offsets[offsetIndex][1]);
if (!isValidCoord(neighborCoord) || !mustProcessCoord(neighborCoord))
continue;
coordQueue.push_back(neighborCoord);
}
coordQueue.pop_front();
}
}
See ? no recursion, just a loop. Pretty much any recursive function can be unwrapped into something like that.
If your underlying platform is restrictive and you have no std::queue, use array (ring buffer implemented as array can act like fifo queue) instead. Because you know size of the board, you can precalculate size of array. The rest should be easy.

Unhandled exception

I try to implement the game described in the http://www.cprogramming.com/tutorial/game_programming/same_game_part1_p2.html . Although it worked well initially, from some point till now crashes at runtime while build does not indicate any error. The problem appears as an “Unhandled Exception”-“Access violation reading location” on the line
return m_arrColors[m_arrBoard[row][col]];
in the function
COLORREF CSameGameBoard::GetBoardSpace(int row, int col)
{
// Check the bounds of the array
if(row < 0 || row >= m_nRows || col < 0 || col >= m_nColumns)
return m_arrColors[0];
return m_arrColors[m_arrBoard[row][col]];
}
Any possible reason?
Update:
The program crashes the first time it tries to access
m_arrColors[m_arrBoard[0][0]];
m_arrColors and m_arrBoard are defined by the constructor:
CSameGameBoard::CSameGameBoard(void)
:m_arrBoard(NULL),
m_nColumns(15), m_nRows(15),
m_nHeight(35), m_nWidth(35)
{
m_arrColors[0] = RGB( 0, 0, 0);
m_arrColors[1] = RGB(255, 0, 0);
m_arrColors[2] = RGB(255,255, 64);
m_arrColors[3] = RGB( 0, 0,255);
}
Update2: I added the command SetupBoard(); in the constructor' s body and it worked. However it is not proposed by the tutorial http://www.cprogramming.com/tutorial/game_programming/same_game_part1_p2.html and initially worked fine in my program without it as well.
The obvious reason is that you're accessing invalid indexes of the arrays - either m_arrColors or m_arrBoard.
For example, if m_arrBoard has dimensions 3x3, and you try to access m_arrBoard[3][3], you'll get a crash (probably, it's actually undefined behavior). - remember that C++ arrays are 0-based.
Run through it with a debugger, and check to see if this is happening.

How to move an item up and down in a wxListCtrl (wxwidgets)

This should be pretty easy but I'm having a heck of a time doing it. Basically I want to move a row in my wxListCtrl up or down. I posted this to wxwidgets forum and got the following code.
m_list->Freeze();
wxListItem item;
item.SetId(item_id); // the one which is selected
m_list->GetItem(item); // Retrieve the item
m_list->DeleteItem(item_id); // Remove it
item.SetId(item_id - 1); // Move it up
m_list->SetItem(item); // Apply it's new pos in the list
m_list->Thaw();
which doesn't work. The element is deleted but not moved up (I guess the setitem line is not working). Then I thought to just switch the text and the image but I can't even get the text from the row reliably. I have
int index = m_right->GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
wxString label = m_right->GetItemText(index);
if(index == 0)
return;
wxListItem item;
item.SetId(index);
bool success = m_right->GetItem(item);
wxString text = item.GetText();
but text is blank even though there is text and the index is correct. So, I'm stuck not even being able to do the most basic task. Anybody know how to do this? The code runs in a button callback (the user presses a little up arrow and my code executes to try to move it). I'm using 2.9.1 on windows.
I made it work like this with wxWidgets 2.9.3 :
void FileSelectionPanel::OnMoveUp( wxCommandEvent& WXUNUSED(evt) )
{
int idx = _listCtrl->GetNextItem( -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
if( idx == 0) idx = _listCtrl->GetNextItem( 0, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
_listCtrl->Freeze();
while( idx > -1 ) {
wxListItem item;
item.SetId(idx); _listCtrl->GetItem(item);
item.SetId(idx-1); _listCtrl->InsertItem(item);
_listCtrl->SetItemData( idx-1, _listCtrl->GetItemData( idx+1 ));
for( int i = 0; i < _listCtrl->GetColumnCount(); i++ ) {
_listCtrl->SetItem( idx-1, i, _listCtrl->GetItemText( idx+1, i ));
}
_listCtrl->DeleteItem( idx + 1 );
idx = _listCtrl->GetNextItem( idx-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED );
}
_listCtrl->Thaw();
}
The thing I noticed it that wxListItem is more of a convenience struct, for storing state of the view and help pass values into the wxListCtrl "nicely". It is in no way bound to what is actually inside of the wxListCtrl.
Hope this still helps anyone !
Even there is already an answer that is checked. I have the same problem here, but my list is unordered. By looking into wxWidgets' code I found out there is another important information inside the wxListItem object - the mask. I got my reordering to work correctly by setting the mask value to -1, which means that all data shall be copied. This includes the item text as well as other information, like the item data (which was important in my case).
wxListItem item;
item.SetId(item_id); // set needed id
item.SetMask(-1); // set needed data
m_list->GetItem(item); // actually retrieve the item
m_list->DeleteItem(item_id); // remove old copy
item.SetId(item_id - 1); // move item up
m_list->InsertItem(item); // insert copy of item
I also had to use "InsertItem" instead of "SetItem". Otherwise, there was no new item inserted, but an existing one overwritten (see also tomcat31's answer).
Is the list ordered? if it is auto ordering it may be ignoring the order you are trying to apply.
From recollection the internal order was not necessarily sequential, you might have to get the index of the previous item and go one before it.