mirror of
https://github.com/Jozufozu/Flywheel.git
synced 2024-12-25 14:36:18 +01:00
Bookkeeping
- Mappings drop pages when they write zero validity bits - Instancer only updates pages that changed
This commit is contained in:
parent
20b3f78b9c
commit
fac63168c1
2 changed files with 69 additions and 44 deletions
|
@ -168,7 +168,7 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||
int otherValid = other.valid.get();
|
||||
|
||||
// If the other page is empty, or we're full, we're done.
|
||||
if (otherValid == 0 || valid == 0xFFFFFFFF) {
|
||||
if (isEmpty(otherValid) || isFull(valid)) {
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
@ -223,15 +223,27 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||
public void update(int modelIndex, int baseInstance) {
|
||||
this.baseInstance = baseInstance;
|
||||
|
||||
if (this.modelIndex == modelIndex && changedPages.isEmpty()) {
|
||||
var sameModelIndex = this.modelIndex == modelIndex;
|
||||
if (sameModelIndex && changedPages.isEmpty()) {
|
||||
// Nothing to do!
|
||||
return;
|
||||
}
|
||||
|
||||
this.modelIndex = modelIndex;
|
||||
|
||||
var pages = this.pages.get();
|
||||
mapping.updateCount(pages.length);
|
||||
|
||||
for (int i = 0; i < pages.length; i++) {
|
||||
mapping.updatePage(i, modelIndex, pages[i].valid.get());
|
||||
if (sameModelIndex) {
|
||||
// Only need to update the changed pages.
|
||||
for (int page = changedPages.nextSetBit(0); page >= 0 && page < pages.length; page = changedPages.nextSetBit(page + 1)) {
|
||||
mapping.updatePage(page, modelIndex, pages[page].valid.get());
|
||||
}
|
||||
} else {
|
||||
// Need to update all pages since the model index changed.
|
||||
for (int i = 0; i < pages.length; i++) {
|
||||
mapping.updatePage(i, modelIndex, pages[i].valid.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -291,46 +303,17 @@ public class IndirectInstancer<I extends Instance> extends AbstractInstancer<I>
|
|||
}
|
||||
|
||||
public void parallelUpdate() {
|
||||
if (true) {
|
||||
// FIXME: infinite loop when the page in readpos doesn't have enough to fill the page in writepos
|
||||
return;
|
||||
}
|
||||
|
||||
var pages = this.pages.get();
|
||||
|
||||
// If there are at least 2 pages with space, we can consolidate.
|
||||
if (fullPages.cardinality() > (pages.length - 2)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note this runs after visuals are updated so we don't really have to take care for thread safety.
|
||||
|
||||
int writePos = 0;
|
||||
|
||||
while (true) {
|
||||
writePos = fullPages.nextClearBit(writePos);
|
||||
int readPos = fullPages.nextClearBit(writePos + 1);
|
||||
|
||||
if (writePos >= pages.length || readPos >= pages.length) {
|
||||
break;
|
||||
}
|
||||
|
||||
InstancePage writeTo = pages[writePos];
|
||||
InstancePage readFrom = pages[readPos];
|
||||
|
||||
int validNow = writeTo.takeFrom(readFrom);
|
||||
|
||||
if (isFull(validNow)) {
|
||||
fullPages.set(writePos);
|
||||
writePos = readPos;
|
||||
}
|
||||
}
|
||||
// TODO: Merge pages when they're less than half full.
|
||||
}
|
||||
|
||||
private static boolean isFull(int valid) {
|
||||
return valid == 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
private static boolean isEmpty(int otherValid) {
|
||||
return otherValid == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
for (IndirectDraw draw : draws()) {
|
||||
|
|
|
@ -13,6 +13,8 @@ public class ObjectStorage extends AbstractArena {
|
|||
public static final int PAGE_SIZE = 1 << LOG_2_PAGE_SIZE;
|
||||
public static final int PAGE_MASK = PAGE_SIZE - 1;
|
||||
|
||||
public static final int INVALID_PAGE = -1;
|
||||
|
||||
public static final int INITIAL_PAGES_ALLOCATED = 4;
|
||||
public static final int DESCRIPTOR_SIZE_BYTES = Integer.BYTES * 2;
|
||||
|
||||
|
@ -53,8 +55,13 @@ public class ObjectStorage extends AbstractArena {
|
|||
|
||||
@Override
|
||||
public void free(int i) {
|
||||
if (i == INVALID_PAGE) {
|
||||
return;
|
||||
}
|
||||
super.free(i);
|
||||
MemoryUtil.memPutInt(ptrForPage(i), 0);
|
||||
var ptr = ptrForPage(i);
|
||||
MemoryUtil.memPutInt(ptr, 0);
|
||||
MemoryUtil.memPutInt(ptr + 4, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -98,14 +105,49 @@ public class ObjectStorage extends AbstractArena {
|
|||
private static final int[] EMPTY_ALLOCATION = new int[0];
|
||||
private int[] pages = EMPTY_ALLOCATION;
|
||||
|
||||
public void updatePage(int i, int modelIndex, int i1) {
|
||||
var ptr = ptrForPage(pages[i]);
|
||||
public void updatePage(int index, int modelIndex, int validBits) {
|
||||
if (validBits == 0) {
|
||||
holePunch(index);
|
||||
return;
|
||||
}
|
||||
var page = pages[index];
|
||||
|
||||
if (page == INVALID_PAGE) {
|
||||
// Un-holed punch.
|
||||
page = unHolePunch(index);
|
||||
}
|
||||
|
||||
var ptr = ptrForPage(page);
|
||||
MemoryUtil.memPutInt(ptr, modelIndex);
|
||||
MemoryUtil.memPutInt(ptr + 4, i1);
|
||||
MemoryUtil.memPutInt(ptr + 4, validBits);
|
||||
|
||||
ObjectStorage.this.needsUpload = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a page on the inside of the mapping, maintaining the same virtual mapping size.
|
||||
*
|
||||
* @param index The index of the page to free.
|
||||
*/
|
||||
public void holePunch(int index) {
|
||||
ObjectStorage.this.free(pages[index]);
|
||||
pages[index] = INVALID_PAGE;
|
||||
|
||||
ObjectStorage.this.needsUpload = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a new page on the inside of the mapping, maintaining the same virtual mapping size.
|
||||
*
|
||||
* @param index The index of the page to allocate.
|
||||
* @return The allocated page.
|
||||
*/
|
||||
private int unHolePunch(int index) {
|
||||
int page = ObjectStorage.this.alloc();
|
||||
pages[index] = page;
|
||||
return page;
|
||||
}
|
||||
|
||||
public void updateCount(int newLength) {
|
||||
var oldLength = pages.length;
|
||||
if (oldLength > newLength) {
|
||||
|
@ -122,8 +164,8 @@ public class ObjectStorage extends AbstractArena {
|
|||
return pages.length;
|
||||
}
|
||||
|
||||
public long page2ByteOffset(int page) {
|
||||
return ObjectStorage.this.byteOffsetOf(pages[page]);
|
||||
public long page2ByteOffset(int index) {
|
||||
return ObjectStorage.this.byteOffsetOf(pages[index]);
|
||||
}
|
||||
|
||||
public void delete() {
|
||||
|
|
Loading…
Reference in a new issue