summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/memory.cpp130
-rw-r--r--src/core/memory.h15
-rw-r--r--src/video_core/rasterizer_accelerated.cpp4
3 files changed, 79 insertions, 70 deletions
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index fb824d710..8c3489ed3 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -225,6 +225,69 @@ struct Memory::Impl {
225 return string; 225 return string;
226 } 226 }
227 227
228 void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
229 if (vaddr == 0) {
230 return;
231 }
232
233 // Iterate over a contiguous CPU address space, which corresponds to the specified GPU
234 // address space, marking the region as un/cached. The region is marked un/cached at a
235 // granularity of CPU pages, hence why we iterate on a CPU page basis (note: GPU page size
236 // is different). This assumes the specified GPU address region is contiguous as well.
237
238 u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1;
239 for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) {
240 Common::PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
241
242 if (cached) {
243 // Switch page type to cached if now cached
244 switch (page_type) {
245 case Common::PageType::Unmapped:
246 // It is not necessary for a process to have this region mapped into its address
247 // space, for example, a system module need not have a VRAM mapping.
248 break;
249 case Common::PageType::Memory:
250 page_type = Common::PageType::RasterizerCachedMemory;
251 current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
252 break;
253 case Common::PageType::RasterizerCachedMemory:
254 // There can be more than one GPU region mapped per CPU region, so it's common
255 // that this area is already marked as cached.
256 break;
257 default:
258 UNREACHABLE();
259 }
260 } else {
261 // Switch page type to uncached if now uncached
262 switch (page_type) {
263 case Common::PageType::Unmapped:
264 // It is not necessary for a process to have this region mapped into its address
265 // space, for example, a system module need not have a VRAM mapping.
266 break;
267 case Common::PageType::Memory:
268 // There can be more than one GPU region mapped per CPU region, so it's common
269 // that this area is already unmarked as cached.
270 break;
271 case Common::PageType::RasterizerCachedMemory: {
272 u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
273 if (pointer == nullptr) {
274 // It's possible that this function has been called while updating the
275 // pagetable after unmapping a VMA. In that case the underlying VMA will no
276 // longer exist, and we should just leave the pagetable entry blank.
277 page_type = Common::PageType::Unmapped;
278 } else {
279 page_type = Common::PageType::Memory;
280 current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
281 }
282 break;
283 }
284 default:
285 UNREACHABLE();
286 }
287 }
288 }
289 }
290
228 /** 291 /**
229 * Maps a region of pages as a specific type. 292 * Maps a region of pages as a specific type.
230 * 293 *
@@ -318,6 +381,10 @@ std::string Memory::ReadCString(VAddr vaddr, std::size_t max_length) {
318 return impl->ReadCString(vaddr, max_length); 381 return impl->ReadCString(vaddr, max_length);
319} 382}
320 383
384void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
385 impl->RasterizerMarkRegionCached(vaddr, size, cached);
386}
387
321void SetCurrentPageTable(Kernel::Process& process) { 388void SetCurrentPageTable(Kernel::Process& process) {
322 current_page_table = &process.VMManager().page_table; 389 current_page_table = &process.VMManager().page_table;
323 390
@@ -334,69 +401,6 @@ bool IsKernelVirtualAddress(const VAddr vaddr) {
334 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; 401 return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
335} 402}
336 403
337void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) {
338 if (vaddr == 0) {
339 return;
340 }
341
342 // Iterate over a contiguous CPU address space, which corresponds to the specified GPU address
343 // space, marking the region as un/cached. The region is marked un/cached at a granularity of
344 // CPU pages, hence why we iterate on a CPU page basis (note: GPU page size is different). This
345 // assumes the specified GPU address region is contiguous as well.
346
347 u64 num_pages = ((vaddr + size - 1) >> PAGE_BITS) - (vaddr >> PAGE_BITS) + 1;
348 for (unsigned i = 0; i < num_pages; ++i, vaddr += PAGE_SIZE) {
349 Common::PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
350
351 if (cached) {
352 // Switch page type to cached if now cached
353 switch (page_type) {
354 case Common::PageType::Unmapped:
355 // It is not necessary for a process to have this region mapped into its address
356 // space, for example, a system module need not have a VRAM mapping.
357 break;
358 case Common::PageType::Memory:
359 page_type = Common::PageType::RasterizerCachedMemory;
360 current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
361 break;
362 case Common::PageType::RasterizerCachedMemory:
363 // There can be more than one GPU region mapped per CPU region, so it's common that
364 // this area is already marked as cached.
365 break;
366 default:
367 UNREACHABLE();
368 }
369 } else {
370 // Switch page type to uncached if now uncached
371 switch (page_type) {
372 case Common::PageType::Unmapped:
373 // It is not necessary for a process to have this region mapped into its address
374 // space, for example, a system module need not have a VRAM mapping.
375 break;
376 case Common::PageType::Memory:
377 // There can be more than one GPU region mapped per CPU region, so it's common that
378 // this area is already unmarked as cached.
379 break;
380 case Common::PageType::RasterizerCachedMemory: {
381 u8* pointer = GetPointerFromVMA(vaddr & ~PAGE_MASK);
382 if (pointer == nullptr) {
383 // It's possible that this function has been called while updating the pagetable
384 // after unmapping a VMA. In that case the underlying VMA will no longer exist,
385 // and we should just leave the pagetable entry blank.
386 page_type = Common::PageType::Unmapped;
387 } else {
388 page_type = Common::PageType::Memory;
389 current_page_table->pointers[vaddr >> PAGE_BITS] = pointer;
390 }
391 break;
392 }
393 default:
394 UNREACHABLE();
395 }
396 }
397 }
398}
399
400u8 Read8(const VAddr addr) { 404u8 Read8(const VAddr addr) {
401 return Read<u8>(addr); 405 return Read<u8>(addr);
402} 406}
diff --git a/src/core/memory.h b/src/core/memory.h
index 47765c8a0..7cd348b49 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -169,6 +169,16 @@ public:
169 */ 169 */
170 std::string ReadCString(VAddr vaddr, std::size_t max_length); 170 std::string ReadCString(VAddr vaddr, std::size_t max_length);
171 171
172 /**
173 * Marks each page within the specified address range as cached or uncached.
174 *
175 * @param vaddr The virtual address indicating the start of the address range.
176 * @param size The size of the address range in bytes.
177 * @param cached Whether or not any pages within the address range should be
178 * marked as cached or uncached.
179 */
180 void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached);
181
172private: 182private:
173 struct Impl; 183 struct Impl;
174 std::unique_ptr<Impl> impl; 184 std::unique_ptr<Impl> impl;
@@ -199,9 +209,4 @@ void WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size);
199void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size); 209void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, std::size_t size);
200void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size); 210void CopyBlock(VAddr dest_addr, VAddr src_addr, std::size_t size);
201 211
202/**
203 * Mark each page touching the region as cached.
204 */
205void RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached);
206
207} // namespace Memory 212} // namespace Memory
diff --git a/src/video_core/rasterizer_accelerated.cpp b/src/video_core/rasterizer_accelerated.cpp
index f3dbadebc..fc6ecb899 100644
--- a/src/video_core/rasterizer_accelerated.cpp
+++ b/src/video_core/rasterizer_accelerated.cpp
@@ -48,9 +48,9 @@ void RasterizerAccelerated::UpdatePagesCachedCount(VAddr addr, u64 size, int del
48 const u64 interval_size = interval_end_addr - interval_start_addr; 48 const u64 interval_size = interval_end_addr - interval_start_addr;
49 49
50 if (delta > 0 && count == delta) { 50 if (delta > 0 && count == delta) {
51 Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true); 51 cpu_memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
52 } else if (delta < 0 && count == -delta) { 52 } else if (delta < 0 && count == -delta) {
53 Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false); 53 cpu_memory.RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
54 } else { 54 } else {
55 ASSERT(count >= 0); 55 ASSERT(count >= 0);
56 } 56 }