diff --git a/rpcs3/Emu/RSX/D3D12/D3D12.h b/rpcs3/Emu/RSX/D3D12/D3D12.h index c0b061c875..069fff3c4b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12.h +++ b/rpcs3/Emu/RSX/D3D12/D3D12.h @@ -88,7 +88,7 @@ D3D12_RESOURCE_DESC getBufferResourceDesc(size_t sizeInByte) } inline -D3D12_RESOURCE_DESC getTexture2DResourceDesc(size_t width, size_t height, DXGI_FORMAT dxgiFormat) +D3D12_RESOURCE_DESC getTexture2DResourceDesc(size_t width, size_t height, DXGI_FORMAT dxgiFormat, size_t mipmapLevels) { D3D12_RESOURCE_DESC result; result = {}; @@ -98,7 +98,7 @@ D3D12_RESOURCE_DESC getTexture2DResourceDesc(size_t width, size_t height, DXGI_F result.Format = dxgiFormat; result.DepthOrArraySize = 1; result.SampleDesc.Count = 1; - result.MipLevels = 1; + result.MipLevels = mipmapLevels; return result; } diff --git a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp index 17b92dab94..28eb929c4b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12GSRender.cpp @@ -545,7 +545,7 @@ D3D12GSRender::D3D12GSRender() m_device->CreateCommittedResource( &hp, D3D12_HEAP_FLAG_NONE, - &getTexture2DResourceDesc(2, 2, DXGI_FORMAT_R8G8B8A8_UNORM), + &getTexture2DResourceDesc(2, 2, DXGI_FORMAT_R8G8B8A8_UNORM, 1), D3D12_RESOURCE_STATE_GENERIC_READ, nullptr, IID_PPV_ARGS(&m_dummyTexture)) @@ -1150,7 +1150,7 @@ void D3D12GSRender::semaphorePGRAPHBackendRelease(u32 offset, u32 value) { D3D12_HEAP_PROPERTIES heapProp = {}; heapProp.Type = D3D12_HEAP_TYPE_DEFAULT; - D3D12_RESOURCE_DESC resdesc = getTexture2DResourceDesc(m_surface_clip_w, m_surface_clip_h, DXGI_FORMAT_R8_UNORM); + D3D12_RESOURCE_DESC resdesc = getTexture2DResourceDesc(m_surface_clip_w, m_surface_clip_h, DXGI_FORMAT_R8_UNORM, 1); resdesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; size_t sizeInByte = m_surface_clip_w * m_surface_clip_h * 2; diff --git a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp index 5a8d776239..7faab5c99b 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12RenderTargetSets.cpp @@ -180,7 +180,7 @@ ID3D12Resource *RenderTargets::bindAddressAsRenderTargets(ID3D12Device *device, D3D12_HEAP_PROPERTIES heapProp = {}; heapProp.Type = D3D12_HEAP_TYPE_DEFAULT; - D3D12_RESOURCE_DESC resourceDesc = getTexture2DResourceDesc(width, height, dxgiFormat); + D3D12_RESOURCE_DESC resourceDesc = getTexture2DResourceDesc(width, height, dxgiFormat, 1); resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; device->CreateCommittedResource( @@ -235,7 +235,7 @@ ID3D12Resource * RenderTargets::bindAddressAsDepthStencil(ID3D12Device * device, assert(0); } - D3D12_RESOURCE_DESC resourceDesc = getTexture2DResourceDesc(width, height, dxgiFormat); + D3D12_RESOURCE_DESC resourceDesc = getTexture2DResourceDesc(width, height, dxgiFormat, 1); resourceDesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL; device->CreateCommittedResource( diff --git a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp index e87cd0eaa7..4b036bf418 100644 --- a/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp +++ b/rpcs3/Emu/RSX/D3D12/D3D12Texture.cpp @@ -136,6 +136,14 @@ D3D12_FILTER getSamplerFilter(u32 minFilter, u32 magFilter) return D3D12_ENCODE_BASIC_FILTER(min, mag, mip, D3D12_FILTER_REDUCTION_TYPE_STANDARD); } +struct MipmapLevelInfo +{ + size_t offset; + size_t width; + size_t height; + size_t rowPitch; +}; + /** * Create a texture residing in default heap and generate uploads commands in commandList, * using a temporary texture buffer. @@ -302,7 +310,7 @@ ID3D12Resource *uploadSingleTexture( size_t rowPitch = powerOf2Align(blockSizeInByte * widthInBlocks, 256); ID3D12Resource *Texture; - size_t textureSize = rowPitch * heightInBlocks; + size_t textureSize = rowPitch * heightInBlocks * 4; // * 3 for mipmap levels assert(textureBuffersHeap.canAlloc(textureSize)); size_t heapOffset = textureBuffersHeap.alloc(textureSize); @@ -321,60 +329,85 @@ ID3D12Resource *uploadSingleTexture( check(Texture->Map(0, nullptr, (void**)&textureData)); // Upload with correct rowpitch - for (unsigned row = 0; row < heightInBlocks; row++) + std::vector mipinfos; + size_t offsetInDst = 0, offsetInSrc = 0; + size_t currentHeight = heightInBlocks, currentWidth = widthInBlocks; + + unsigned tmp = texture.GetMipmap(); + if (tmp > 1) + printf("here"); + for (unsigned mipLevel = 0; mipLevel < texture.GetMipmap(); mipLevel++) { - switch (format) + MipmapLevelInfo currentMipmapLevelInfo = {}; + currentMipmapLevelInfo.offset = offsetInDst; + currentMipmapLevelInfo.height = currentHeight; + currentMipmapLevelInfo.width = currentWidth; + + for (unsigned row = 0; row < currentHeight; row++) { - case CELL_GCM_TEXTURE_A8R8G8B8: - { - if (is_swizzled) + switch (format) { - u32 *src, *dst; - u32 log2width, log2height; + case CELL_GCM_TEXTURE_A8R8G8B8: + { + currentMipmapLevelInfo.rowPitch = powerOf2Align(currentWidth * blockSizeInByte, 256); + if (is_swizzled) + { + u32 *src, *dst; + u32 log2width, log2height; - src = (u32*)pixels; - dst = (u32*)textureData; + src = (u32*)pixels + offsetInSrc; + dst = (u32*)textureData + offsetInDst; - log2width = (u32)(logf((float)w) / logf(2.f)); - log2height = (u32)(logf((float)h) / logf(2.f)); + log2width = (u32)(logf((float)currentWidth) / logf(2.f)); + log2height = (u32)(logf((float)currentHeight) / logf(2.f)); + +#pragma omp parallel for + for (int j = 0; j < w; j++) + dst[(row * currentMipmapLevelInfo.rowPitch / 4) + j] = src[LinearToSwizzleAddress(j, row, 0, log2width, log2height, 0)]; + } + else + memcpy((char*)textureData + offsetInDst + row * currentMipmapLevelInfo.rowPitch, (char*)pixels + offsetInSrc + row * currentWidth * blockSizeInByte, currentWidth * blockSizeInByte); + break; + } + case CELL_GCM_TEXTURE_A4R4G4B4: + case CELL_GCM_TEXTURE_R5G6B5: + { + currentMipmapLevelInfo.rowPitch = rowPitch; + unsigned short *dst = (unsigned short *)textureData, *src = (unsigned short *)pixels; - #pragma omp parallel for for (int j = 0; j < w; j++) - dst[(row * rowPitch / 4) + j] = src[LinearToSwizzleAddress(j, row, 0, log2width, log2height, 0)]; + { + u16 tmp = src[offsetInSrc / 2 + row * srcPitch / 2 + j]; + dst[offsetInDst / 2 + row * rowPitch / 2 + j] = (tmp >> 8) | (tmp << 8); + } + break; } - else - streamBuffer((char*)textureData + row * rowPitch, (char*)pixels + row * srcPitch, srcPitch); - break; - } - case CELL_GCM_TEXTURE_A4R4G4B4: - case CELL_GCM_TEXTURE_R5G6B5: - { - unsigned short *dst = (unsigned short *)textureData, *src = (unsigned short *)pixels; - - for (int j = 0; j < w; j++) + case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: { - u16 tmp = src[row * srcPitch / 2 + j]; - dst[row * rowPitch / 2 + j] = (tmp >> 8) | (tmp << 8); - } - break; - } - case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT: - { - unsigned short *dst = (unsigned short *)textureData, *src = (unsigned short *)pixels; + currentMipmapLevelInfo.rowPitch = rowPitch; + unsigned short *dst = (unsigned short *)textureData, *src = (unsigned short *)pixels; - for (int j = 0; j < w * 4; j++) - { - unsigned short tmp = src[row * w * 4 + j]; - dst[row * w * 4 + j] = (tmp >> 8) | (tmp << 8); + for (int j = 0; j < w * 4; j++) + { + unsigned short tmp = src[offsetInSrc / 2 + row * w * 4 + j]; + dst[offsetInDst / 2 + row * w * 4 + j] = (tmp >> 8) | (tmp << 8); + } + break; + } + default: + { + currentMipmapLevelInfo.rowPitch = rowPitch; + streamBuffer((char*)textureData + offsetInDst + row * rowPitch, (char*)pixels + offsetInSrc + row * srcPitch, srcPitch); + break; + } } - break; - } - default: - { - streamBuffer((char*)textureData + row * rowPitch, (char*)pixels + row * srcPitch, srcPitch); - break; - } } + offsetInDst += currentHeight * currentMipmapLevelInfo.rowPitch; + offsetInDst = powerOf2Align(offsetInDst, 256); + offsetInSrc += currentHeight * currentWidth * blockSizeInByte; + mipinfos.push_back(currentMipmapLevelInfo); + currentHeight /= 2; + currentWidth /= 2; } Texture->Unmap(0, nullptr); @@ -387,25 +420,33 @@ ID3D12Resource *uploadSingleTexture( check(device->CreatePlacedResource( textureHeap.m_heap, heapOffset2, - &getTexture2DResourceDesc(w, h, dxgiFormat), + &getTexture2DResourceDesc(w, h, dxgiFormat, texture.GetMipmap()), D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&vramTexture) )); textureHeap.m_resourceStoredSinceLastSync.push_back(std::make_tuple(heapOffset2, textureSize, vramTexture)); - D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {}; - dst.pResource = vramTexture; - dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; - src.pResource = Texture; - src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; - src.PlacedFootprint.Footprint.Depth = 1; - src.PlacedFootprint.Footprint.Width = (UINT)w; - src.PlacedFootprint.Footprint.Height = (UINT)h; - src.PlacedFootprint.Footprint.RowPitch = (UINT)rowPitch; - src.PlacedFootprint.Footprint.Format = dxgiFormat; - commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + size_t miplevel = 0; + for (const MipmapLevelInfo mli : mipinfos) + { + D3D12_TEXTURE_COPY_LOCATION dst = {}, src = {}; + dst.pResource = vramTexture; + dst.SubresourceIndex = miplevel; + dst.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src.PlacedFootprint.Offset = mli.offset; + src.pResource = Texture; + src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + src.PlacedFootprint.Footprint.Depth = 1; + src.PlacedFootprint.Footprint.Width = (UINT)mli.width; + src.PlacedFootprint.Footprint.Height = (UINT)mli.height; + src.PlacedFootprint.Footprint.RowPitch = (UINT)mli.rowPitch; + src.PlacedFootprint.Footprint.Format = dxgiFormat; + + commandList->CopyTextureRegion(&dst, 0, 0, 0, &src, nullptr); + miplevel++; + } D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; @@ -461,7 +502,7 @@ size_t D3D12GSRender::UploadTextures() D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D; srvDesc.Format = dxgiFormat; - srvDesc.Texture2D.MipLevels = 1; + srvDesc.Texture2D.MipLevels = m_textures[i].GetMipmap(); switch (format) {