/// <summary> /// Translates virtual texture address to physical rectangle in physical texture. /// </summary> /// <param name="address"></param> /// <param name="rectangle"></param> /// <returns>False if address is not presented in cache</returns> public bool TranslateAddress(VTAddress address, VTTile tile, out Rectangle rectangle) { Page page; if (cache.TryGetValue(address, out page)) { var pa = page.Address; var ppc = pageCount; var size = VTConfig.PageSizeBordered; int x = (pa % ppc) * size; int y = (pa / ppc) * size; int w = size; int h = size; rectangle = new Rectangle(x, y, w, h); page.Tile = tile; return(true); } else { rectangle = new Rectangle(); return(false); } }
/// <summary> /// Request texture loading /// </summary> /// <param name="address"></param> public void RequestTile(VTAddress address) { #if USE_PRIORITY_QUEUE requestQueue.Enqueue(address.MipLevel, address); #else requestQueue.Enqueue(address); #endif }
/// <summary> /// Clears cache /// </summary> public void Purge() { cache = new LRUCache <VTAddress, Page>(capacity); // fill cache with dummy pages : for (int i = 0; i < capacity; i++) { var va = VTAddress.CreateBadAddress(i); var page = new Page(va, i, pageCount, physTexSize); cache.Add(va, page); } }
public Page(VTAddress va, int pa, int physPageCount, int physicalTexSize) { this.VA = va; this.Address = pa; var physTexSize = (float)physicalTexSize; var border = VTConfig.PageBorderWidth; var pageSize = VTConfig.PageSizeBordered; this.X = ((pa % physPageCount) * pageSize + border) / physTexSize; this.Y = ((pa / physPageCount) * pageSize + border) / physTexSize; }
/// <summary> /// Adds new page to cache. /// /// If page exists: /// - LFU index of existing page is shifted. /// - returns FALSE /// /// If page with given address does not exist: /// - page added to cache. /// - some pages could be evicted /// - return TRUE /// /// </summary> /// <param name="address"></param> /// <returns></returns> public bool Add(VTAddress virtualAddress, out int physicalAddress) { Page page; if (dictionary.TryGetValue(virtualAddress, out page)) { page.LfuIndex |= (byte)0x1; physicalAddress = page.Address; return(false); } else { if (GetFreePhysicalAddress(out physicalAddress)) { page = new Page(virtualAddress, physicalAddress, VTConfig.PhysicalPageCount); table[physicalAddress] = page; dictionary.Add(virtualAddress, page); return(true); } else { page = GetPageToDiscard(); physicalAddress = page.Address; dictionary.Remove(page.VA); page = new Page(virtualAddress, physicalAddress, VTConfig.PhysicalPageCount); table[physicalAddress] = page; dictionary.Add(virtualAddress, page); return(true); } } }
/// <summary> /// Adds new page to cache. /// /// If page exists: /// - LFU index of existing page is shifted. /// - returns FALSE /// /// If page with given address does not exist: /// - page added to cache. /// - some pages could be evicted /// - return TRUE /// /// </summary> /// <param name="address"></param> /// <returns>False if page is already exist</returns> public bool Add(VTAddress virtualAddress, out int physicalAddress) { Page page; if (cache.TryGetValue(virtualAddress, out page)) { physicalAddress = page.Address; return(false); } else { cache.Discard(out page); var newPage = new Page(virtualAddress, page.Address, pageCount, physTexSize); cache.Add(virtualAddress, newPage); physicalAddress = newPage.Address; return(true); } }
/// <summary> /// /// </summary> /// <param name="camera"></param> /// <param name="depthBuffer"></param> /// <param name="hdrTarget"></param> /// <param name="diffuse"></param> /// <param name="specular"></param> /// <param name="normals"></param> internal void RenderGBuffer(GameTime gameTime, StereoEye stereoEye, Camera camera, HdrFrame frame, RenderWorld rw, bool staticOnly) { using (new PixEvent("RenderGBuffer")) { if (surfaceShader == null) { return; } if (rs.SkipSceneRendering) { return; } var device = Game.GraphicsDevice; var view = camera.GetViewMatrix(stereoEye); var projection = camera.GetProjectionMatrix(stereoEye); var viewPosition = camera.GetCameraPosition4(stereoEye); var cbData = new CBMeshInstanceData(); var cbDataSubset = new CBSubsetData(); var hdr = frame.HdrBuffer.Surface; var depth = frame.DepthBuffer.Surface; var gbuffer0 = frame.GBuffer0.Surface; var gbuffer1 = frame.GBuffer1.Surface; var feedback = frame.FeedbackBuffer.Surface; device.ResetStates(); device.SetTargets(depth, hdr, gbuffer0, gbuffer1, feedback); device.PixelShaderSamplers[0] = SamplerState.LinearPointClamp; device.PixelShaderSamplers[1] = SamplerState.PointClamp; device.PixelShaderSamplers[2] = SamplerState.AnisotropicClamp; var instances = rw.Instances; if (instances.Any()) { device.PixelShaderResources[1] = rs.VTSystem.PageTable; device.PixelShaderResources[2] = rs.VTSystem.PhysicalPages0; device.PixelShaderResources[3] = rs.VTSystem.PhysicalPages1; device.PixelShaderResources[4] = rs.VTSystem.PhysicalPages2; } //#warning INSTANSING! foreach (var instance in instances) { if (!instance.Visible) { continue; } if (staticOnly && !instance.Static) { continue; } cbData.View = view; cbData.Projection = projection; cbData.World = instance.World; cbData.ViewPos = viewPosition; cbData.Color = instance.Color; cbData.ViewBounds = new Vector4(hdr.Width, hdr.Height, hdr.Width, hdr.Height); cbData.VTPageScaleRCP = rs.VTSystem.PageScaleRCP; constBuffer.SetData(cbData); device.PixelShaderConstants[0] = constBuffer; device.VertexShaderConstants[0] = constBuffer; device.PixelShaderConstants[1] = constBufferSubset; device.SetupVertexInput(instance.vb, instance.ib); if (instance.IsSkinned) { constBufferBones.SetData(instance.BoneTransforms); device.VertexShaderConstants[3] = constBufferBones; } try { device.PipelineState = factory[(int)(SurfaceFlags.GBUFFER | SurfaceFlags.RIGID)]; foreach (var subset in instance.Subsets) { var vt = rw.VirtualTexture; var rect = vt.GetTexturePosition(subset.Name); cbDataSubset.Rectangle = new Vector4(rect.X, rect.Y, rect.Width, rect.Height); constBufferSubset.SetData(cbDataSubset); device.PixelShaderConstants[1] = constBufferSubset; device.DrawIndexed(subset.PrimitiveCount * 3, subset.StartPrimitive * 3, 0); } rs.Counters.SceneDIPs++; } catch (UbershaderException e) { Log.Warning(e.Message); ExceptionDialog.Show(e); } } // // downsample feedback buffer and readback it to virtual texture : // rs.Filter.StretchRect(frame.FeedbackBufferRB.Surface, frame.FeedbackBuffer, SamplerState.PointClamp); var feedbackBuffer = new VTAddress[HdrFrame.FeedbackBufferWidth * HdrFrame.FeedbackBufferHeight]; frame.FeedbackBufferRB.GetFeedback(feedbackBuffer); rs.VTSystem.Update(feedbackBuffer, gameTime); } }
/// <summary> /// /// </summary> /// <param name="data"></param> public void Update(VTAddress[] data, GameTime gameTime) { var feedback = data.Distinct().Where(p => p.Dummy != 0).ToArray(); ApplyVTState(); List <VTAddress> feedbackTree = new List <VTAddress>(); // // Build tree : // foreach (var addr in feedback) { var paddr = addr; feedbackTree.Add(paddr); while (paddr.MipLevel < VTConfig.MaxMipLevel) { paddr = VTAddress.FromChild(paddr); feedbackTree.Add(paddr); } } // // Distinct : // feedbackTree = feedbackTree // .Where( p0 => cache.Contains(p0) ) .Distinct() .OrderBy(p1 => p1.MipLevel) .ToList(); //*/ // // Detect thrashing and prevention // Get highest mip, remove them, repeat until no thrashing occur. // while (feedbackTree.Count >= tileCache.Capacity / 2) { int minMip = feedbackTree.Min(va => va.MipLevel); feedbackTree.RemoveAll(va => va.MipLevel == minMip); } if (LockTiles) { feedbackTree.Clear(); } if (tileCache != null) { } // // Put into cache : // if (tileCache != null && tileLoader != null) { foreach (var addr in feedbackTree) { int physAddr; if (tileCache.Add(addr, out physAddr)) { //Log.Message("...vt tile cache: {0} --> {1}", addr, physAddr ); tileLoader.RequestTile(addr); } } } // // update table : // if (tileLoader != null && tileCache != null) { for (int i = 0; i < MaxPPF; i++) { VTTile tile; if (tileLoader.TryGetTile(out tile)) { Rectangle rect; if (tileCache.TranslateAddress(tile.VirtualAddress, tile, out rect)) { var sz = VTConfig.PageSizeBordered; if (RandomColor) { tile.FillRandomColor(); } if (ShowTileCheckers) { tile.DrawChecker(); } if (ShowTileAddress) { tile.DrawText(fontImage, 16, 16, tile.VirtualAddress.ToString()); tile.DrawText(fontImage, 16, 32, string.Format("{0} {1}", rect.X / sz, rect.Y / sz)); tile.DrawText(fontImage, 16, 48, Math.Floor(stopwatch.Elapsed.TotalMilliseconds).ToString()); } if (ShowTileBorder) { tile.DrawBorder(); } //PhysicalPages.SetData( 0, rect, tile.Data, 0, tile.Data.Length ); tileStamper?.Add(tile, rect); } } } // emboss tiles to physical texture tileStamper?.Update(this, gameTime.ElapsedSec); // update page table : UpdatePageTable(); } }