diff options
Diffstat (limited to 'src/blitter')
-rw-r--r-- | src/blitter/ntapi_blt_alloc.c | 149 | ||||
-rw-r--r-- | src/blitter/ntapi_blt_block.c | 204 | ||||
-rw-r--r-- | src/blitter/ntapi_blt_free.c | 48 |
3 files changed, 401 insertions, 0 deletions
diff --git a/src/blitter/ntapi_blt_alloc.c b/src/blitter/ntapi_blt_alloc.c new file mode 100644 index 0000000..4ba6f2c --- /dev/null +++ b/src/blitter/ntapi_blt_alloc.c @@ -0,0 +1,149 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include <ntapi/nt_status.h> +#include <ntapi/nt_blitter.h> +#include <ntapi/nt_sync.h> +#include <ntapi/ntapi.h> +#include <ntapi/nt_atomic.h> +#include "ntapi_blitter.h" +#include "ntapi_impl.h" + +static int __blt_popcount(uintptr_t mask) +{ + /* todo: check cpuid, use at_popcount */ + int i,ret; + + for (i=0,ret=0; i<8*sizeof(uintptr_t); i++) + if (mask & ((uintptr_t)1<<i)) + ret++; + + return ret; +} + + +int32_t __fastcall __ntapi_blt_alloc( + __out nt_blitter ** blitter, + __in nt_blitter_params * params) +{ + int32_t status; + nt_blitter * blt_ctx; + size_t blt_ctx_size; + size_t params_size; + size_t ptrs,i; + + /* alignment */ + if ((params->block_size % sizeof(uintptr_t)) || (params->block_count % sizeof(uintptr_t))) + return NT_STATUS_INVALID_PARAMETER; + + /* blt control block allocation */ + ptrs = params->block_count / (8 * sizeof(uintptr_t)); + blt_ctx = (nt_blitter *)0; + blt_ctx_size = (size_t)&((nt_blitter *)0)->bits; + + /* user-provided bitmap? */ + if (!params->bitmap) + blt_ctx_size += ptrs * sizeof(uintptr_t); + + /* alloc */ + status = __ntapi->zw_allocate_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + (void **)&blt_ctx, + 0, + &blt_ctx_size, + NT_MEM_COMMIT, + NT_PAGE_READWRITE); + + if (status) return (status); + + /* init control block */ + __ntapi->tt_aligned_block_memset( + blt_ctx, + 0,(size_t)&((nt_blitter *)0)->bits); + + blt_ctx->addr = blt_ctx; + blt_ctx->size = blt_ctx_size; + blt_ctx->ptrs = ptrs; + + /* init bitmap */ + blt_ctx->bitmap = params->bitmap + ? (uintptr_t *)params->bitmap + : blt_ctx->bits; + + if (!(params->flags & NT_BLITTER_PRESERVE_BITS)) + __ntapi->tt_aligned_block_memset( + blt_ctx->bitmap, + (intptr_t)0xFFFFFFFFFFFFFFFF, + ptrs * sizeof(uintptr_t)); + + /* info structure */ + blt_ctx->info.info_size = sizeof(nt_blitter_info); + blt_ctx->info.block_count = params->block_count; + blt_ctx->info.block_size = params->block_size; + + if (params->flags & NT_BLITTER_ENABLE_BLOCK_ARRAY) + /* allocate in place */ + blt_ctx->info.region_size = params->block_count * params->block_size; + else + /* use pointer array */ + blt_ctx->info.region_size = params->block_count * sizeof(uintptr_t); + + /* allocate region */ + if (params->region) + blt_ctx->info.region_addr = params->region; + else + status = __ntapi->zw_allocate_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + &blt_ctx->info.region_addr, + 0, + &blt_ctx->info.region_size, + NT_MEM_COMMIT, + NT_PAGE_READWRITE); + + if (status) { + __ntapi->blt_free(blt_ctx); + return status; + } + + if (params->flags & NT_BLITTER_PRESERVE_BITS) + for (i=0,blt_ctx->info.blocks_avail=0; i<ptrs; i++) + blt_ctx->info.blocks_avail += __blt_popcount(blt_ctx->bitmap[i]); + else + blt_ctx->info.blocks_avail = params->block_count; + + if (params->flags & NT_BLITTER_ENABLE_BLOCK_ARRAY) + blt_ctx->info.blocks_cached = params->block_count; + + /* init block array */ + if (!params->region) + __ntapi->tt_aligned_block_memset( + blt_ctx->info.region_addr, + 0,blt_ctx->info.region_size); + + /* copy params */ + if (params->params_size < sizeof(nt_blitter_params)) + params_size = params->params_size; + else + params_size = sizeof(nt_blitter_params); + + __ntapi->tt_aligned_block_memcpy( + (uintptr_t *)&blt_ctx->params, + (uintptr_t *)params, + params_size); + + /* update params */ + blt_ctx->params.lock_tries = params->lock_tries + ? params->lock_tries + : __NT_BLITTER_DEFAULT_LOCK_TRIES; + + blt_ctx->params.round_trips = params->round_trips + ? params->round_trips + : __NT_BLITTER_DEFAULT_ROUND_TRIPS; + + *blitter = blt_ctx; + + return NT_STATUS_SUCCESS; +} diff --git a/src/blitter/ntapi_blt_block.c b/src/blitter/ntapi_blt_block.c new file mode 100644 index 0000000..879eb1b --- /dev/null +++ b/src/blitter/ntapi_blt_block.c @@ -0,0 +1,204 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include <ntapi/nt_status.h> +#include <ntapi/nt_blitter.h> +#include <ntapi/nt_sync.h> +#include <ntapi/ntapi.h> +#include <ntapi/nt_atomic.h> +#include "ntapi_blitter.h" +#include "ntapi_impl.h" + +static int32_t __fastcall __blt_bitbite( + __in nt_blitter * blitter, + __in unsigned int bit, + __in size_t byte) +{ + uint32_t locktry; + uintptr_t test; + uintptr_t cmp; + uintptr_t xchg; + uintptr_t mask; + + mask = ((uintptr_t)1 << bit); + locktry = blitter->params.lock_tries; + + for (; locktry; locktry--) { + cmp = blitter->bitmap[byte] | mask; + xchg = cmp ^ mask; + + test = at_locked_cas( + (intptr_t *)&blitter->bitmap[byte], + cmp,xchg); + + if (test == cmp) { + at_locked_dec(&blitter->info.blocks_avail); + at_locked_inc(&blitter->info.blocks_used); + return NT_STATUS_SUCCESS; + + } else if (test ^ mask) + return NT_STATUS_TRANSACTIONAL_CONFLICT; + } + + if (!locktry) { + blitter->info.busy = 1; + blitter->info.lock_tries = blitter->params.lock_tries; + return NT_STATUS_DEVICE_BUSY; + } + + return NT_STATUS_MORE_PROCESSING_REQUIRED; +} + +static int32_t __fastcall __blt_acquire( + __in nt_blitter * blitter, + __out intptr_t * blkid) +{ + unsigned int bit; + uintptr_t i,n; + + if (blitter->info.blocks_avail == 0) + return NT_STATUS_ALLOCATE_BUCKET; + + for (n=0,bit=0; blitter->info.blocks_avail && (n < blitter->params.round_trips); n++) { + for (i=*blkid/(8*sizeof(size_t)); (i<blitter->ptrs); i++) + if (at_bsf(&bit,blitter->bitmap[i])) + break; + + if (i == blitter->ptrs) + return NT_STATUS_ALLOCATE_BUCKET; + + switch (__blt_bitbite(blitter,bit,i)) { + case NT_STATUS_SUCCESS: + *blkid = bit + (i * 8 * sizeof(size_t)); + return NT_STATUS_SUCCESS; + + case NT_STATUS_DEVICE_BUSY: + return NT_STATUS_DEVICE_BUSY; + + default: + break; + } + } + + return NT_STATUS_ALLOCATE_BUCKET; +} + + +int32_t __fastcall __ntapi_blt_obtain( + __in nt_blitter * blitter, + __out intptr_t * blkid) +{ + unsigned int bit; + uintptr_t i,n; + uintptr_t mask; + + if (blitter->info.blocks_avail == 0) + return NT_STATUS_ALLOCATE_BUCKET; + else if ((bit = *blkid % sizeof(size_t)) == 0) + return __ntapi_blt_acquire(blitter,blkid); + + for (n=0,mask=(uintptr_t)-1; n<bit; n++) + mask ^= ((size_t)1 << n); + + i = *blkid / (8*sizeof(size_t)); + + for (n=0; blitter->info.blocks_avail && (n < blitter->params.round_trips); n++) { + if (!(at_bsf(&bit,(mask & blitter->bitmap[i])))) + break; + + switch (__blt_bitbite(blitter,bit,i)) { + case NT_STATUS_SUCCESS: + *blkid = bit + (i * 8 * sizeof(size_t)); + return NT_STATUS_SUCCESS; + + case NT_STATUS_DEVICE_BUSY: + return NT_STATUS_DEVICE_BUSY; + + default: + break; + } + } + + *blkid = ++i * 8 * sizeof(size_t); + return __blt_acquire(blitter,blkid); +} + + +int32_t __fastcall __ntapi_blt_possess( + __in nt_blitter * blitter, + __out intptr_t * blkid) +{ + int bit; + size_t byte; + uintptr_t test; + uintptr_t mask; + + bit = *blkid % (8*sizeof(size_t)); + byte = *blkid / (8*sizeof(size_t)); + + mask = ((uintptr_t)1 << bit); + test = at_locked_and( + (intptr_t *)&blitter->bitmap[byte], + ~mask); + + if (test & mask) { + at_locked_dec(&blitter->info.blocks_avail); + at_locked_inc(&blitter->info.blocks_used); + } + + return NT_STATUS_SUCCESS; +} + + +int32_t __fastcall __ntapi_blt_acquire( + __in nt_blitter * blitter, + __out intptr_t * blkid) +{ + *blkid = 0; + return __blt_acquire(blitter,blkid); +} + + +int32_t __fastcall __ntapi_blt_release( + __in nt_blitter * blitter, + __out intptr_t blkid) +{ + size_t i; + unsigned int idx; + uintptr_t bit; + + i = blkid / (8 * sizeof(uintptr_t)); + idx = blkid % (8 * sizeof(uintptr_t)); + bit = ((uintptr_t)1 << idx); + + at_locked_or((intptr_t *)&blitter->bitmap[i],bit); + at_locked_dec(&blitter->info.blocks_used); + at_locked_inc(&blitter->info.blocks_avail); + + return NT_STATUS_SUCCESS; +} + + +void * __fastcall __ntapi_blt_get( + __in const nt_blitter * blitter, + __in intptr_t block_id) +{ + size_t * addr = (size_t *)blitter->info.region_addr; + addr += block_id; + return addr; +} + + +void __fastcall __ntapi_blt_set( + __in const nt_blitter * blitter, + __in intptr_t block_id, + __in void * val) +{ + size_t * addr = (size_t *)blitter->info.region_addr; + addr += block_id; + *addr = (size_t)val; + return; +} diff --git a/src/blitter/ntapi_blt_free.c b/src/blitter/ntapi_blt_free.c new file mode 100644 index 0000000..a5956b1 --- /dev/null +++ b/src/blitter/ntapi_blt_free.c @@ -0,0 +1,48 @@ +/********************************************************/ +/* ntapi: Native API core library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.NTAPI. */ +/********************************************************/ + +#include <ntapi/nt_status.h> +#include <ntapi/nt_blitter.h> +#include <ntapi/nt_sync.h> +#include <ntapi/ntapi.h> +#include "ntapi_blitter.h" +#include "ntapi_impl.h" + +int32_t __fastcall __ntapi_blt_free(nt_blitter * blt_ctx) +{ + int32_t status; + void * region_addr; + size_t region_size; + + /* validation */ + if (!blt_ctx) return NT_STATUS_INVALID_PARAMETER; + + /* free blt block */ + region_addr = blt_ctx->info.region_addr; + region_size = blt_ctx->info.region_size; + + if (region_size && !blt_ctx->params.region) { + status = __ntapi->zw_free_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + ®ion_addr, + ®ion_size, + NT_MEM_RELEASE); + + if (status) return status; + } + + /* free blt control block */ + region_addr = blt_ctx->addr; + region_size = blt_ctx->size; + + status = __ntapi->zw_free_virtual_memory( + NT_CURRENT_PROCESS_HANDLE, + ®ion_addr, + ®ion_size, + NT_MEM_RELEASE); + + return status; +} |