VOGONS


Test Drive 5 Glide3x not working

Topic actions

Reply 20 of 32, by Dege

User metadata
Rank l33t
Rank
l33t
kjliew wrote on 2021-04-02, 05:16:

Does dgVoodoo2 really make use of level n mipmaps downloaded from Glide calls?

Yes. It takes the grTexSource and grTexMultibaseAddress calls seriously.
Texturing emulates the linear texture memory and any texture descriptor fed by these calls is used in an exact way, no matter what potential memory garbage is at the given texture memory location (like with a real hardware).
grTexDownloadMipmap and the other functions are just ways in various forms to manipulate the linear memory content, nothing more.

I cannot debug now but meanwhile I noticed from the dgVoodoo call-log that TD5 doesn't feed Glide with mipmapped textures.
SmallLod and LargeLod were the same in all grTexDownloadMipmap and grTexsource calls.
So, I don't understand how mipmapping takes place through QEmu.

Could you make a log with the dgv debug version for that plz?

@Robertmo: thanks, some day I'll have a look at it.

Reply 21 of 32, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie
Dege wrote on 2021-04-02, 13:04:

... I noticed from the dgVoodoo call-log that TD5 doesn't feed Glide with mipmapped textures.
SmallLod and LargeLod were the same in all grTexDownloadMipmap and grTexsource calls.

Are you sure? That wasn't right. In my previous post what I attached call trace comparing nGlide and dgVoodoo2, they both showed smallLod != largeLod for several calls.
Here's the dgvoodoo2.log from debug version and there are multiple calls grTexDownloadMipMap() and grTexSource() that smallLod != largeLod.

Regarding grTexSource(), I hope that you won't be touching the "info->data" pointer, the data should have been downloaded with grTexDownloadMipMap(). Unlike grTexDownloadMipMap(), grTexSource() is a hot function within rendering loop, so pushing redundant data will incur considerable performance hit. QEMU makes such assumption in Glide pass-through data marshalling.

Perhaps I should reimplement the same static texture cache similar with DOSBox.

Attachments

  • Filename
    dgvoodoo2.log.7z
    File size
    1.03 MiB
    Downloads
    4 downloads
    File license
    Fair use/fair dealing exception

Reply 22 of 32, by Dege

User metadata
Rank l33t
Rank
l33t

Yes, there were no mipmapping when running natively.

Regarding grTexSource(), I hope that you won't be touching the "info->data" pointer, the data should have been downloaded with grTexDownloadMipMap().

Of course not, that member isn't even valid for that call.

Anyway, I managed to launch the game from Qemu, fxmemmap.vxd was missing.
However, I run into a crash right at entering a quick race.
grGetVertexLayout crashes because the incoming pointer is invalid, pointing to an unmapped area.
Am I using an old version of something?

Reply 23 of 32, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie
Dege wrote on 2021-04-02, 21:39:

Am I using an old version of something?

If you didn't build from latest GIT, then maybe. I lost track of what version I had given you last time.
You should always build from latest GIT. If not, I can always furnish a copy for you.

I think I found the real culprit -- NumberOfTMUs
The MIPMAP corruption only showed up with NumberOfTMUs > 1 regardless of Voodoo card type. Configured as voodoo_graphics with 2 TMUs had the same MIPMAP corruption.
With NumferOfTMUs = 1, both TD5 and Ultim@te Race Pro render correctly.

Reply 25 of 32, by Dege

User metadata
Rank l33t
Rank
l33t
robertmo wrote on 2021-04-03, 00:53:

Thanks!! I'll try it!

kjliew wrote on 2021-04-02, 22:04:

I think I found the real culprit -- NumberOfTMUs
The MIPMAP corruption only showed up with NumberOfTMUs > 1 regardless of Voodoo card type. Configured as voodoo_graphics with 2 TMUs had the same MIPMAP corruption.
With NumferOfTMUs = 1, both TD5 and Ultim@te Race Pro render correctly.

Yes, it's suspicious for me too. Looking at the log, the game splits mipmaps between TMU0 and 1.
There are grTexDownloadMipmap calls with evenOdd==GR_MIPMAPLEVELMASK_EVEN and evenOdd==GR_MIPMAPLEVELMASK_ODD.
You call grTexTextureMemRequired before them to calc the size of texture data to copy, but for non-BOTH cases this function only calcs the size of every other mipmaps summed up (because of the layout in the texture memory) while grTexDownloadMipmap requires a pointer to the whole mipmap data to upload from.
Couldn't that be a problem? grTexCalcMemRequired seems to better fit here.

But anyway, I'm going to give debugging a try again.
Oh, and plz, could you add releases for the dll's on your GitHub page?

Reply 26 of 32, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie
Dege wrote on 2021-04-03, 07:04:
Yes, it's suspicious for me too. Looking at the log, the game splits mipmaps between TMU0 and 1. There are grTexDownloadMipmap c […]
Show full quote

Yes, it's suspicious for me too. Looking at the log, the game splits mipmaps between TMU0 and 1.
There are grTexDownloadMipmap calls with evenOdd==GR_MIPMAPLEVELMASK_EVEN and evenOdd==GR_MIPMAPLEVELMASK_ODD.
You call grTexTextureMemRequired before them to calc the size of texture data to copy, but for non-BOTH cases this function only calcs the size of every other mipmaps summed up (because of the layout in the texture memory) while grTexDownloadMipmap requires a pointer to the whole mipmap data to upload from.
Couldn't that be a problem? grTexCalcMemRequired seems to better fit here.

So if I understand that correctly, the size calculation was incorrect because oddEven != both. Then I can just always force oddEven=both to calculate the size, info->data pointer from the game will always have the full MIPMAP and dgVoodoo2 will find out the offset for odd/even MIPMAP from info->data pointer to download. I want to be very sure about this because the guest stub may have faulted if it read more than the info->data pointer actually has.

Dege wrote on 2021-04-03, 07:04:

But anyway, I'm going to give debugging a try again.
Oh, and plz, could you add releases for the dll's on your GitHub page?

Let me check out your theory, it is a quick & easy for me. Otherwise, I will send the full latest build into your PM.

Reply 27 of 32, by Dege

User metadata
Rank l33t
Rank
l33t
kjliew wrote on 2021-04-03, 07:36:

So if I understand that correctly, the size calculation was incorrect because oddEven != both. Then I can just always force oddEven=both to calculate the size, info->data pointer from the game will always have the full MIPMAP and dgVoodoo2 will find out the offset for odd/even MIPMAP from info->data pointer to download. I want to be very sure about this because the guest stub may have faulted if it read more than the info->data pointer actually has.

Yes, exactly. The design in mind about those functions was the following (IMO), from the perspective of coding against Glide: you have a full mipmap in system memory, coming from a 3df file or whatever but you want to split its even/odd mipmap levels to different TMU memories. The easiest (and compatible) way is just telling grTexDownloadMipmap what "type" of mipmap levels to upload to the memory while providing the same pointer to the whole mipmap-set and let grTexDownloadMipmap find out what levels to upload where. To be able to increment your texture memory addresses in the texture upload process, grTexTextureMemRequired tells you the effective amount of memory needed on a TMU for the both/even/odd case while grTexCalcMemRequired always tells you the size of the whole mipmap-set which can be used for operations in system memory.

Let me check out your theory, it is a quick & easy for me. Otherwise, I will send the full latest build into your PM.

Thanks, that'd be cool!

Reply 28 of 32, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie

Yes, your theory is right and it fixes both TD5 and Ultim@te Race Pro. It amazed me that no one had actually caught this even for DOSBox. It seems that not many Glide games really know how to use both TMUs.

So my next question, how about the guTexDownloadMipMap()? This one dgVoodoo2 would allocate memory from guTexAllocateMemory() and return mmid. I guess it should be the same then that the src pointer should be the size of _BOTH instead of the oddEven given to guTexAllocationMemory().

Do you know any Glide games that actually make use of grTexMultibase/grTexMultibaseAddress?

Reply 29 of 32, by Dege

User metadata
Rank l33t
Rank
l33t

Great!!

Splitting mipmap levels to 2 TMUs is only for achieving trilinear filtering, and I don't think that too many games messed with that back in the days when only Voodoo2 had 2 TMUs.
Probably none of the DOS Glide games and that's why it didn't turn out through DosBox. If it's a problem there at all, I don't know the code of Gulikoza's patch, maybe copying the mipmap data is unnecessary there.
Btw, why is it needed in QEmu? Isn't guest memory visible to host dll's? Or the guest has an internal page-mapping, so it's memory is not necessarily contiguous to the host?

guTexAllocateMemory just stores the incoming parameters in an internal table and allocates TMU memory by calling grTexTextureMemRequired (tmuId, evenOdd).
guTexDownloadMipmap is just a wrapper around grTexDownloadMipmap, so it expects the same ptr and knows the evenOdd paramter from the previously stored guTexAllocateMemory parameters.
So yes, they're just helper functions and work the same way.

Multibase textures: no, unfortunately I can't recall any game using that. But it shouldn't be a problem as it has no anything to do with downloading mipmaps.
IIRC, grTexsource is equivalent to calling grTexMultibaseAddress (tmu, GR_TEXBASE_256, startAddress, evenOdd, info).

Reply 30 of 32, by kjliew

User metadata
Rank Oldbie
Rank
Oldbie
Dege wrote on 2021-04-03, 12:22:

Splitting mipmap levels to 2 TMUs is only for achieving trilinear filtering, and I don't think that too many games messed with that back in the days when only Voodoo2 had 2 TMUs.
Probably none of the DOS Glide games and that's why it didn't turn out through DosBox. If it's a problem there at all, I don't know the code of Gulikoza's patch, maybe copying the mipmap data is unnecessary there.
Btw, why is it needed in QEmu? Isn't guest memory visible to host dll's? Or the guest has an internal page-mapping, so it's memory is not necessarily contiguous to the host?

Yeah, back in those days, bilinear filtering was already jaw-dropping on 640x480 screen. No game would probably care to implement trilinear filtering, or they would just do with 2-pass on single TMU.

Gulikoza's Glide patch for DOSBox has similar issue when oddEven!=_BOTH, but he had static texture cache and host simply pulled the data from guest into the cache. I guess we were just being cautious not to copy more than it was needed. 3Dfx documentation wasn't very clear about this and grTexTextureMemRequired() semantic matched that of grTexDownloadMipMap().

Yes, you're right, guest memory can be made visible to host DLLs, but to get good performance with acceleration, instead of taking VMEXIT to have the host pull the data, the guest pushes data into FIFO to batch up as many Glide calls as possible. The FIFO is device memory from guest perspective and not subject to guest OS paging. Otherwise, simply translating guest PA to host VA then passing the pointer to dgVoodoo2, it is not guaranteed that the entire data have been paged in prior to VMEXIT. The theory is to have host induce a guest page fault to make the memory available, but I do not know how to do that 😜. Yeah, host-pull is simpler than guest-push and I started with that, too. Prior to getting acceleration working, I just had the guest stubs dummy read the entire data to make sure they were already paged in before taking VMEXIT.

Reply 31 of 32, by Dege

User metadata
Rank l33t
Rank
l33t

Thanks for the explanation!
So, it's basically because of batched execution. And even without that, from the host side it'd be hard to force keeping the needed guest pages in a paged-in state for the time of the call.
Now I understand.

but then it could break if any game ever played tricks with mipmaps and downloaded level n mipmaps that were not really the same as level 0. I don't know if such trick is even possible ...

Yes, it's very possible. In the DX7 D3D SDK there is a sample app where the mipmap levels of a texture consist of bitmaps of numbers. 1, 2, 3...
So, depending on the view point you can read which mipmap level can actually be seen. 😀