端游引擎 讲解2

direct封装api

struct _gpu_t : public gpu_t
{
    //d3d
    d3d_t                                    d3d;
    byte4                                    ordinal;

    //identifier
    D3DADAPTER_IDENTIFIER9                    identifier;

    //hardware caps
    gpu_caps_t                                hardware_caps;

    //d3d device
    d3ddevice_t                                device;

    //working caps
    gpu_caps_t                                working_caps;

    //pipeline initialization parameters
    gpu_creation_parameters_t                cur_cp;
    gpu_presentation_parameters_t            cur_pp;

    //decl pool
    map<byte4, d3ddecl_t>                    decl_map;        //fvf -> decl

    //dynamic vertex buffer
    d3dvb_t                                    dynvb;
    byte4                                    dynvb_size;
    byte4                                    dynvb_used_bytes;
    bool                                    dynvb_broken;

    //global render states
    matrix                                    mat_view;
    matrix                                    mat_proj;
    matrix                                    mat_viewproj;
    matrix                                    mat_viewproj_transpose;
    matrix                                    mat_viewprojviewport;
    D3DVIEWPORT9                            cur_viewport;
    byte4                                    viewproj_vsconst_reg;            // -1 for unmapped
    vector<global_vsconst_def_t>            global_vsconst_vec;

    //static render states
    vector< static_render_states_t >        srs_vec;
    vector< vector<transition_info_t> >        transition_table;
    byte4                                    cur_srs;                        //0 for the default one

    //dynamic render states
    dynamic_render_states_t                    cur_drs;

    //init / clear (called by d3d init()/shutdown() only)
    bool init(d3d_t _d3d, byte4 _ordinal);        //fail if the HAL-device is not-available
    void clear() {}                                //nothing to clear

    //identifier
    const D3DADAPTER_IDENTIFIER9*    get_identifier() {return &identifier;}

    //current display mode
    void                            get_current_display_mode(D3DDISPLAYMODE* mode) {d3d->GetAdapterDisplayMode(ordinal, mode);}

    //static caps
    const gpu_caps_t*                get_hardware_caps() {return &hardware_caps;}
    gpu_vertex_processing_method_t    calc_vertex_processing_level();
    byte4                            build_valid_presentation_parameter_combos(BOOL multisample, buffer_t* out);

    //pipeline control
    bool    turn_on(const gpu_creation_parameters_t* cp, const gpu_presentation_parameters_t* pp);
    void    turn_off();
    bool    reset(const gpu_presentation_parameters_t* pp);
    bool    begin_scene() {return SUCCEEDED(device->BeginScene());}
    bool    end_scene() {return SUCCEEDED(device->EndScene());}
    bool    present();
    bool    test_cooperative_level();

    //creation parameters
    const gpu_creation_parameters_t*        get_creation_parameters() {return &cur_cp;}
    const gpu_presentation_parameters_t*    get_presentation_parameters() {return &cur_pp;}

    //dynamic caps
    const gpu_caps_t*    get_working_caps() {return &working_caps;}
    byte4                build_valid_render_target_formats(buffer_t* out);
    byte4                build_valid_render_target_texture_formats(buffer_t* out);
    byte4                build_valid_offscr_texture_formats(buffer_t* out);
    byte4                build_valid_downsampling_target_formats(buffer_t* out);
    byte4                build_valid_downsampling_source_formats(D3DFORMAT target_format, buffer_t* out);

    //static objects
    bool    create_vertex_buffer(byte4 length, byte4 usage, byte4 fvf, D3DPOOL pool, d3dvb_t* out) {return SUCCEEDED(device->CreateVertexBuffer(length, usage, fvf, pool, out, 0));}                                      //创建定点buffer
    bool    create_index_buffer(byte4 length, byte4 usage, D3DFORMAT format, D3DPOOL pool, d3dib_t* out) {return SUCCEEDED(device->CreateIndexBuffer(length, usage, format, pool, out, 0));}               //创建索引buffer
    bool    create_offscr_surface(byte4 width, byte4 height, D3DFORMAT format, D3DPOOL pool, d3dsurface_t* out) {return SUCCEEDED(device->CreateOffscreenPlainSurface(width, height, format, pool, out, 0));}
    bool    create_render_target(byte4 width, byte4 height, D3DFORMAT format, D3DMULTISAMPLE_TYPE multisample_type, byte4 multisample_quality, bool lockable, d3dsurface_t* out) {return SUCCEEDED(device->CreateRenderTarget(width, height, format, multisample_type, multisample_quality, lockable, out, 0));} //创建纹理
    bool    create_texture(byte4 width, byte4 height, byte4 levels, byte4 usage, D3DFORMAT format, D3DPOOL pool, d3dtexture_t* out) {return SUCCEEDED(device->CreateTexture(width, height, levels, usage, format, pool, out, 0));}
    bool    create_vertex_shader(const byte4* bytecode, d3dvs_t* out) {return SUCCEEDED(device->CreateVertexShader(bytecode, out));}

    //decl pool
    bool    create_vertex_declaration(byte4 fvf, d3ddecl_t* out);

    //dynamic vertex buffer
    void    set_dynamic_vertex_buffer_size(byte4 size);
    void*    lock_dynamic_vertex_buffer(byte4 vertex_count, byte4 stride, byte4* start_vertex, d3dvb_t* vertex_buffer);
    void    unlock_dynamic_vertex_buffer();

    //global render states
    void                set_view_matrix(const matrix* view);
    void                set_proj_matrix(const matrix* proj);
    void                set_viewport(const D3DVIEWPORT9* viewport);
    const matrix*        get_view_matrix()                {return &mat_view;}
    const matrix*        get_proj_matrix()                {return &mat_proj;}
    const matrix*        get_viewproj_matrix()            {return &mat_viewproj;}
    const matrix*        get_viewproj_transpose_matrix()    {return &mat_viewproj_transpose;}
    const D3DVIEWPORT9*    get_viewport()                    {return &cur_viewport;}
    const matrix*        get_viewprojviewport_matrix()    {return &mat_viewprojviewport;}
    void                map_viewproj_to_vsconst(byte4 reg);
    void                set_global_vsconst(byte4 reg, const float* data, byte4 float4_count);
    void                set_render_target(d3dsurface_t rt)    {device->SetRenderTarget(0, rt);}
    void                get_render_target(d3dsurface_t* rt) {device->GetRenderTarget(0, rt);}

    //static render states
    byte4    define_static_render_states(const static_render_states_t* in);
    void    set_static_render_states(byte4 id);

    //dynamic render states
    void    set_software_vertex_processing(bool software);
    void    set_stream_source(d3dvb_t vertex_buffer, byte4 stride);
    void    set_indices(d3dib_t index_buffer);
    void    set_fvf(byte4 fvf);
    void    set_decl(d3ddecl_t decl);
    void    set_vertex_shader(d3dvs_t vertex_shader);
    void    set_vertex_shader_constants(byte4 start_register, const float* data, byte4 float4_count);
    void    set_vertex_blend(D3DVERTEXBLENDFLAGS vertex_blend);
    void    set_indexed_vertex_blend_enable(bool enable);
    void    set_world_matrix(byte4 index, const matrix* world_matrix);
    void    set_texture(d3dtexture_t texture);
    void    set_texture_factor(byte4 factor);
    
    //draw
    void    draw_primitive(D3DPRIMITIVETYPE primitive_type, byte4 start_vertex, byte4 primitive_count) {device->DrawPrimitive(primitive_type, start_vertex, primitive_count);}
    void    draw_indexed_primitive(D3DPRIMITIVETYPE primitive_type, int base_vertex_index, byte4 min_vertex_index, byte4 num_vertices, byte4 start_index, byte4 primitive_count) {device->DrawIndexedPrimitive(primitive_type, base_vertex_index, min_vertex_index, num_vertices, start_index, primitive_count);}

    //surface operations
    bool    clear_target(byte4 count, const D3DRECT* rects, byte4 flags, D3DCOLOR color, float z, byte4 stencil) {return SUCCEEDED(device->Clear(0, 0, flags, color, z, stencil));}
    bool    update_texture(d3dtexture_t src, d3dtexture_t dst) {return SUCCEEDED(device->UpdateTexture(src, dst));}
    bool    stretch_rect(d3dsurface_t src, const RECT* src_rect, d3dsurface_t dst, const RECT* dst_rect, D3DTEXTUREFILTERTYPE filter) {return SUCCEEDED(device->StretchRect(src, src_rect, dst, dst_rect, filter));}
    bool    color_fill(d3dsurface_t surface, const RECT* rect, D3DCOLOR color) {return SUCCEEDED(device->ColorFill(surface, rect, color));}
    bool    get_render_target_data(d3dsurface_t rt, d3dsurface_t dst) {return SUCCEEDED(device->GetRenderTargetData(rt, dst));}
    bool    get_front_buffer_data(d3dsurface_t dst) {return SUCCEEDED(device->GetFrontBufferData(0, dst));}

    //d3d device exposed for D3DX lib
    d3ddevice_t    d3ddevice() {return device;}

    //internal routines
    void reflect_global_states();
    void force_default_dynamic_states();
};

bool _gpu_t::init(d3d_t _d3d, byte4 _ordinal)
{
    //check that whether this is a valid HAL device
    D3DCAPS9 d3dcaps;
    if(FAILED(_d3d->GetDeviceCaps(_ordinal, D3DDEVTYPE_HAL, &d3dcaps)))
        return false;
    
    //d3d
    d3d = _d3d;

    //adapter ordinal
    ordinal = _ordinal;

    //identifier
    _d3d->GetAdapterIdentifier(_ordinal, 0, &identifier);

    //hardware caps
    translate_caps(&d3dcaps, &hardware_caps);

    //device
    device = 0;

    //working caps defaults to hardware caps
    translate_caps(&d3dcaps, &working_caps);

    //cur_cp, cup_pp is undefined now
    memset(&cur_cp, 0, sizeof(cur_cp));
    memset(&cur_pp, 0, sizeof(cur_pp));

    //no dynamic vertex buffer
    dynvb = 0;
    dynvb_size = 0;
    dynvb_used_bytes = 0;
    dynvb_broken = false;

    //global states is undefined now
    D3DXMatrixIdentity(&mat_view);
    D3DXMatrixIdentity(&mat_proj);
    D3DXMatrixIdentity(&mat_viewproj);
    D3DXMatrixIdentity(&mat_viewproj_transpose);
    D3DXMatrixIdentity(&mat_viewprojviewport);
    memset(&cur_viewport, 0, sizeof(cur_viewport));
    viewproj_vsconst_reg = -1;

    //static states is undefined now
    cur_srs = -1;

    //dynamic states is undefined now
    memset(&cur_drs, 0, sizeof(cur_drs));

    return true;
}

gpu_vertex_processing_method_t _gpu_t::calc_vertex_processing_level()
{
    D3DCAPS9 d3dcaps;
    d3d->GetDeviceCaps(ordinal, D3DDEVTYPE_HAL, &d3dcaps);
    return (d3dcaps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) ? ((d3dcaps.DevCaps & D3DDEVCAPS_PUREDEVICE) ? _gpu_vertex_processing_method_purehardware_ : _gpu_vertex_processing_method_hardware_) : _gpu_vertex_processing_method_software_;
}

byte4 _gpu_t::build_valid_presentation_parameter_combos(BOOL multisample, buffer_t* out)
{
    //current display mode
    D3DDISPLAYMODE cur_display_mode;
    d3d->GetAdapterDisplayMode(ordinal, &cur_display_mode);

    //build the set of all valid display_modes (ignore refresh-rate)
    vector<D3DDISPLAYMODE>    display_mode_vec;
    display_mode_vec.reserve(128);

    //ensure that the current display mode is in
    display_mode_vec.push_back(cur_display_mode);
    display_mode_vec[0].RefreshRate = 0;                //ignore refresh-rate

    const D3DFORMAT allowed_display_fmt_vec[] =
    {
            D3DFMT_X1R5G5B5, 
            D3DFMT_R5G6B5,
            D3DFMT_X8R8G8B8, 
            D3DFMT_A2R10G10B10,
    };
    const byte4 allowed_display_fmt_count  = sizeof(allowed_display_fmt_vec) / sizeof(allowed_display_fmt_vec[0]);

    for(byte4 ifmt = 0; ifmt < allowed_display_fmt_count; ifmt++)
    {
        byte4 mode_count = d3d->GetAdapterModeCount(ordinal, allowed_display_fmt_vec[ifmt]);
        for(byte4 imode = 0; imode < mode_count; imode++)
        {
            D3DDISPLAYMODE display_mode;
            d3d->EnumAdapterModes(ordinal, allowed_display_fmt_vec[ifmt], imode, &display_mode);

            //ignore refresh-rate
            bool exist = false;
            for(byte4 inow = 0; inow < display_mode_vec.size(); inow++)
            {
                if(    display_mode_vec[inow].Format == display_mode.Format &&
                    display_mode_vec[inow].Width == display_mode.Width     &&
                    display_mode_vec[inow].Height == display_mode.Height )
                {
                    exist = true;
                    break;
                }
            }
            if(!exist)
            {
                display_mode.RefreshRate = 0;
                display_mode_vec.push_back(display_mode);
            }
        }
    }

    //build the set of all possible backbuffer formats
    const D3DFORMAT bkbuf_fmt_vec[] = 
    {   
            D3DFMT_X1R5G5B5,
            D3DFMT_A1R5G5B5,
            D3DFMT_R5G6B5,
            D3DFMT_X8R8G8B8,
            D3DFMT_A8R8G8B8,
            D3DFMT_A2R10G10B10,
    };
    const byte4 bkbuf_fmt_count = sizeof(bkbuf_fmt_vec) / sizeof(bkbuf_fmt_vec[0]);

    //build the set of all possible depth-stencil formats (ignore lockable formats)
    const D3DFORMAT ds_fmt_vec[] = 
    {   
            D3DFMT_D16,
            D3DFMT_D15S1,
            D3DFMT_D24X8,
            D3DFMT_D24S8,
            D3DFMT_D24X4S4,
            D3DFMT_D32,
            D3DFMT_D24FS8,
    };
    const byte4 ds_fmt_count = sizeof(ds_fmt_vec) / sizeof(ds_fmt_vec[0]); 

    //build the set of all windowed-fullscreen states
    const bool windowed_vec[] = {true, false};

    //build the set of all gdi-dialogbox states
    const bool dialogbox_support_vec[] = {true, false};

    //loop all the combos, filter out invalid ones, and collect the remains
    vector<gpu_presentation_parameters_t>    valid_pp_vec;
    valid_pp_vec.reserve(1024);

    gpu_presentation_parameters_t pp;

    //backbuffer count is only constrained by video memory (we use discard swap-effect)
    pp.backbuffer_count = 0;

    for(int iwin = 0; iwin < 2; iwin++)
    {
        pp.windowed = windowed_vec[iwin];

        for(int idb = 0; idb < 2; idb++)
        {
            pp.gdi_dialogbox_support = dialogbox_support_vec[idb];

            //dialog box is always supported in windowd mode
            if(windowed_vec[iwin] && !dialogbox_support_vec[idb])
                continue;

            for(byte4 imode = 0; imode < display_mode_vec.size(); imode++)
            {
                pp.display_mode = display_mode_vec[imode];

                if(windowed_vec[iwin])
                {
                    //in windowed mode, backbuffer size is arbitrary
                    pp.backbuffer_width = 0;
                    pp.backbuffer_height = 0;
                }
                else
                {
                    //in fullscreen mode, backbuffer size should be the same as the display resolution
                    pp.backbuffer_width =  display_mode_vec[imode].Width;
                    pp.backbuffer_height =  display_mode_vec[imode].Height;
                }

                //windowed = true ==> display_mode = cur_display_mode
                if(windowed_vec[iwin])
                {
                    if( display_mode_vec[imode].Format != cur_display_mode.Format ||
                        display_mode_vec[imode].Width != cur_display_mode.Width ||
                        display_mode_vec[imode].Height != cur_display_mode.Height )
                    {
                        continue;
                    }
                }

                for(byte4 ibk = 0; ibk < bkbuf_fmt_count; ibk++)
                {
                    pp.backbuffer_format = bkbuf_fmt_vec[ibk];

                    //in fullscreen mode, if dialog box is supported, bkbuf_fmt should be one of the {D3DFMT_X1R5G5B5, D3DFMT_R5G6B5, D3DFMT_X8R8G8B8}
                    if(!windowed_vec[iwin] && dialogbox_support_vec[idb])
                    {
                        if(    bkbuf_fmt_vec[ibk] != D3DFMT_X1R5G5B5 &&
                            bkbuf_fmt_vec[ibk] != D3DFMT_R5G6B5 &&
                            bkbuf_fmt_vec[ibk] != D3DFMT_X8R8G8B8 )
                        {
                            continue;
                        }
                    }

                    //the backbuffer should be a render target
                    if(FAILED(d3d->CheckDeviceFormat(ordinal, D3DDEVTYPE_HAL, display_mode_vec[imode].Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, bkbuf_fmt_vec[ibk]))) 
                        continue;

                    //post pixel shader blending is required
                    if(FAILED(d3d->CheckDeviceFormat(ordinal, D3DDEVTYPE_HAL, display_mode_vec[imode].Format, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, bkbuf_fmt_vec[ibk]))) 
                        continue;

                    //(windowed, display_fmt, bkbuf_fmt) combo should pass the CheckDeviceType() check
                    if(FAILED(d3d->CheckDeviceType(ordinal, D3DDEVTYPE_HAL, display_mode_vec[imode].Format, bkbuf_fmt_vec[ibk], windowed_vec[iwin])))
                        continue;

                    for(byte4 ids = 0; ids < ds_fmt_count; ids++)
                    {
                        pp.depthstencil_format = ds_fmt_vec[ids];

                        //it should be a depth-stencil target
                        if(FAILED(d3d->CheckDeviceFormat(ordinal, D3DDEVTYPE_HAL, display_mode_vec[imode].Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, ds_fmt_vec[ids]))) 
                            continue;

                        //match with render-target
                        if(FAILED(d3d->CheckDepthStencilMatch(ordinal, D3DDEVTYPE_HAL, display_mode_vec[imode].Format, bkbuf_fmt_vec[ibk], ds_fmt_vec[ids])))
                            continue;

                        //D3DMULTISAMPLE_NONE is always valid, so we find one, add it
                        pp.multisample_type = D3DMULTISAMPLE_NONE;
                        pp.multisample_quality = 0;
                        valid_pp_vec.push_back(pp);

                        //in fullscreen mode, if dialog box is supported, multisample should be none
                        if(!windowed_vec[iwin] && dialogbox_support_vec[idb])
                            continue;
                        
                        //if the multisample is not needed, continue
                        if(!multisample)
                            continue;

                        for(byte4 ms_type = 1; ms_type <= 16; ms_type++)
                        {
                            pp.multisample_type = (D3DMULTISAMPLE_TYPE)ms_type;

                            //the ms type should be supported by the render-target format
                            byte4 bk_quality_level_count;
                            if(FAILED(d3d->CheckDeviceMultiSampleType(ordinal, D3DDEVTYPE_HAL, bkbuf_fmt_vec[ibk], windowed_vec[iwin], (D3DMULTISAMPLE_TYPE)ms_type, &bk_quality_level_count)))
                                continue;

                            //the ms type should be supported by the depth-stencil format
                            byte4 ds_quality_level_count;
                            if(FAILED(d3d->CheckDeviceMultiSampleType(ordinal, D3DDEVTYPE_HAL, ds_fmt_vec[ids], windowed_vec[iwin], (D3DMULTISAMPLE_TYPE)ms_type, &ds_quality_level_count)))
                                continue;

                            //get max quality
                            byte4 max_quality_level_count = min(bk_quality_level_count, ds_quality_level_count);
                            for(byte4 quality = 0; quality < max_quality_level_count; quality++)
                            {
                                pp.multisample_quality = quality;

                                //find one, add it
                                valid_pp_vec.push_back(pp);
                            }
                        }
                    }
                }
            }
        }
    }

    if(valid_pp_vec.empty())
        return 0;

    buffer_t buf;
    D3DXCreateBuffer((byte4)valid_pp_vec.size() * sizeof(gpu_presentation_parameters_t), &buf);
    memcpy(buf->GetBufferPointer(), &valid_pp_vec[0], buf->GetBufferSize());
    *out = buf;

    return (byte4)valid_pp_vec.size();
}

void _gpu_t::reflect_global_states()
{
    //view / proj (shadowed -> board)
    device->SetTransform(D3DTS_VIEW, &mat_view);
    device->SetTransform(D3DTS_PROJECTION, &mat_proj);
    if( viewproj_vsconst_reg != -1 )
    {
        device->SetVertexShaderConstantF(viewproj_vsconst_reg, (float*)&mat_viewproj_transpose, 4);
    }

    //viewport (board -> shadowed)
    device->GetViewport(&cur_viewport);
    matrix mat_viewport;
    build_viewport_matrix(&mat_viewport, &cur_viewport);
    mat_viewprojviewport = mat_viewproj * mat_viewport;

    //global vs consts (shadowed -> board)
    for( byte4 i = 0; i < global_vsconst_vec.size(); i++ )
    {
        device->SetVertexShaderConstantF(global_vsconst_vec[i].start_reg, (float*)&global_vsconst_vec[i].data[0], (byte4)global_vsconst_vec[i].data.size());
    }
}

void _gpu_t::force_default_dynamic_states()
{
    if( cur_cp.vertex_processing_method == _gpu_vertex_processing_method_mixed_ )
    {
        device->SetSoftwareVertexProcessing(false);
        cur_drs.software_vertex_processing = false;
    }

    device->SetStreamSource(0, 0, 0, 0);
    cur_drs.vertex_buffer = 0;
    cur_drs.stride = 0;

    device->SetIndices(0);
    cur_drs.index_buffer = 0;

    device->SetVertexDeclaration(0);
    device->SetFVF(0);
    cur_drs.use_fvf = true;
    cur_drs.fvf = 0;
    cur_drs.decl = 0;

    device->SetVertexShader(0);
    cur_drs.vertex_shader = 0;

    device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);
    cur_drs.vertex_blend = D3DVBF_DISABLE;

    device->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, false);
    cur_drs.indexed_vertex_blend_enable = false;

    device->SetTexture(0, 0);
    cur_drs.texture = 0;

    device->SetRenderState(D3DRS_TEXTUREFACTOR, 0xffffffff);
    cur_drs.texture_factor = 0xffffffff;
}

bool _gpu_t::turn_on(const gpu_creation_parameters_t* cp, const gpu_presentation_parameters_t* pp)
{
    //create device
    D3DDEVICE_CREATION_PARAMETERS    d3dcp;
    D3DPRESENT_PARAMETERS            d3dpp;

    translate_initialization_parameters(ordinal, cp, pp, &d3dcp, &d3dpp);

    HRESULT hr = d3d->CreateDevice(d3dcp.AdapterOrdinal, d3dcp.DeviceType, d3dcp.hFocusWindow, d3dcp.BehaviorFlags, &d3dpp, &device);
    if(FAILED(hr))
    {
        switch(hr)
        {
        case D3DERR_INVALIDCALL:        _error_record_ = _gpu_error_invalid_params_; break;
        case D3DERR_OUTOFVIDEOMEMORY:    _error_record_ = _gpu_error_out_of_video_memory_; break;
        case D3DERR_NOTAVAILABLE:        _error_record_ = _gpu_error_hardware_acceleration_not_available_; break;
        default:                        _error_record_ = _gpu_error_unknown_; break;
        }

        //fail creating device. didn't touch anything except the error record
        return false;
    }

    //apply dialog box mode
    if( !pp->windowed )
    {
        device->SetDialogBoxMode( pp->gdi_dialogbox_support );
    }

    //working caps
    D3DCAPS9 d3dcaps;
    device->GetDeviceCaps(&d3dcaps);
    translate_caps(&d3dcaps, &working_caps);

    //save creation/presentation parameters;
    cur_cp = *cp;
    cur_pp = *pp;

    //global states
    reflect_global_states();

    //define default static states and set it as the current one
    static_render_states_t default_srs;

    default_srs.lighting                = true;
    default_srs.cull_mode                = D3DCULL_CCW;
    default_srs.alpha_test_enable        = false;
    default_srs.alpha_ref                = 0;
    default_srs.alpha_func                = D3DCMP_ALWAYS;
    default_srs.z_enable                = D3DZB_TRUE;
    default_srs.z_func                    = D3DCMP_LESSEQUAL;
    default_srs.z_write_enable            = true;
    default_srs.alpha_blend_enable        = false;
    default_srs.blend_op                = D3DBLENDOP_ADD;
    default_srs.src_blend                = D3DBLEND_ONE;
    default_srs.dest_blend                = D3DBLEND_ZERO;
    default_srs.color_op                = D3DTOP_MODULATE;
    default_srs.color_arg1                = D3DTA_TEXTURE;
    default_srs.color_arg2                = D3DTA_CURRENT;
    default_srs.alpha_op                = D3DTOP_SELECTARG1;
    default_srs.alpha_arg1                = D3DTA_TEXTURE;
    default_srs.alpha_arg2                = D3DTA_CURRENT;
    default_srs.address_u                = D3DTADDRESS_WRAP;
    default_srs.address_v                = D3DTADDRESS_WRAP;
    default_srs.mag_filter                = D3DTEXF_POINT;
    default_srs.min_filter                = D3DTEXF_POINT;

    define_static_render_states(&default_srs);        //the returned id will be 0
    cur_srs = 0;

    //dynamic states
    force_default_dynamic_states();

    return true;
}

void _gpu_t::turn_off()
{
    //release dynamic vertex buffer
    SAFE_RELEASE(dynvb);
    dynvb_size = 0;
    dynvb_used_bytes = 0;
    dynvb_broken = false;

    //clear static states
    for( byte4 i = 0; i < transition_table.size(); i++ )
    {
        for( byte4 j = 0; j < transition_table[i].size(); j++ )
        {
            transition_table[i][j].clear();
        }
    }
    srs_vec.clear();
    transition_table.clear();
    cur_srs = -1;

    //release decls
    map<byte4, d3ddecl_t>::iterator pdecl = decl_map.begin();
    while( pdecl != decl_map.end() )
    {
        SAFE_RELEASE(pdecl->second);
        pdecl++;
    }
    decl_map.clear();

    //now all the device objects are destroyed, we can release the device
    SAFE_RELEASE(device);
//    if( device->Release() > 0 )    //for debugging & testing purpose
//        MessageBox(0, "The D3D device has a non-zero reference count, meaning some objects were not released.", "Warning", MB_ICONERROR|MB_OK);
//    device = 0;

    //default working caps to hardware caps after turned off
    D3DCAPS9 d3dcaps;
    d3d->GetDeviceCaps(ordinal, D3DDEVTYPE_HAL, &d3dcaps);
    translate_caps(&d3dcaps, &working_caps);

    //creation/presentation is undefined now
    memset(&cur_cp, 0, sizeof(cur_cp));
    memset(&cur_pp, 0, sizeof(cur_pp));

    //clear global states
    D3DXMatrixIdentity(&mat_view);
    D3DXMatrixIdentity(&mat_proj);
    D3DXMatrixIdentity(&mat_viewproj);
    D3DXMatrixIdentity(&mat_viewproj_transpose);
    D3DXMatrixIdentity(&mat_viewprojviewport);
    memset(&cur_viewport, 0, sizeof(cur_viewport));
    viewproj_vsconst_reg = -1;
    global_vsconst_vec.clear();

    //clear dynamic states
    memset(&cur_drs, 0, sizeof(cur_drs));
}

bool _gpu_t::reset(const gpu_presentation_parameters_t* pp)
{
    //release dynamic vertex buffer (it will be recreated lazily after resetting successfully)
    SAFE_RELEASE(dynvb);
    dynvb_used_bytes = 0;
    dynvb_broken = false;

    //release stateblocks (they will be recreated lazily after resetting successfully)
    for( byte4 i = 0; i < transition_table.size(); i++ )
    {
        for( byte4 j = 0; j < transition_table[i].size(); j++ )
        {
            transition_table[i][j].discard_video_objects();
        }
    }

    //now all the video objects are discarded, we can reset the device (decls are not video objects)
    D3DPRESENT_PARAMETERS d3dpp;
    translate_initialization_parameters(ordinal, &cur_cp, pp, 0, &d3dpp);

    HRESULT hr = device->Reset(&d3dpp);
    if( FAILED(hr) )
    {
        switch(hr)
        {
        case D3DERR_INVALIDCALL:            _error_record_ = _gpu_error_invalid_params_; break;
        case D3DERR_OUTOFVIDEOMEMORY:        _error_record_ = _gpu_error_out_of_video_memory_; break;
        case D3DERR_DEVICELOST:                _error_record_ = _gpu_error_device_lost_; break;
        case D3DERR_DRIVERINTERNALERROR:    _error_record_ = _gpu_error_driver_internal_error_; break;
        default:                            _error_record_ = _gpu_error_unknown_; break;
        }
        return false;
    }

    //apply dialog box mode
    if( !pp->windowed )
    {
        device->SetDialogBoxMode( pp->gdi_dialogbox_support );
    }

    //update cur_pp after successfully resetting
    cur_pp = *pp;

    //reflect global states
    reflect_global_states();

    //force to default static states
    device->SetRenderState(D3DRS_LIGHTING,                true);
    device->SetRenderState(D3DRS_CULLMODE,                D3DCULL_CCW);
    device->SetRenderState(D3DRS_ALPHATESTENABLE,        false);
    device->SetRenderState(D3DRS_ALPHAREF,                0);
    device->SetRenderState(D3DRS_ALPHAFUNC,                D3DCMP_ALWAYS);
    device->SetRenderState(D3DRS_ZENABLE,                D3DZB_TRUE);
    device->SetRenderState(D3DRS_ZFUNC,                    D3DCMP_LESSEQUAL);
    device->SetRenderState(D3DRS_ZWRITEENABLE,            true);
    device->SetRenderState(D3DRS_ALPHABLENDENABLE,        false);
    device->SetRenderState(D3DRS_BLENDOP,                D3DBLENDOP_ADD);
    device->SetRenderState(D3DRS_SRCBLEND,                D3DBLEND_ONE);
    device->SetRenderState(D3DRS_DESTBLEND,                D3DBLEND_ZERO);

    device->SetTextureStageState(0, D3DTSS_COLOROP,        D3DTOP_MODULATE);
    device->SetTextureStageState(0, D3DTSS_COLORARG1,    D3DTA_TEXTURE);
    device->SetTextureStageState(0, D3DTSS_COLORARG2,    D3DTA_CURRENT);
    device->SetTextureStageState(0, D3DTSS_ALPHAOP,        D3DTOP_SELECTARG1);
    device->SetTextureStageState(0, D3DTSS_ALPHAARG1,    D3DTA_TEXTURE);
    device->SetTextureStageState(0, D3DTSS_ALPHAARG2,    D3DTA_CURRENT);

    device->SetSamplerState(0, D3DSAMP_ADDRESSU,        D3DTADDRESS_WRAP);
    device->SetSamplerState(0, D3DSAMP_ADDRESSV,        D3DTADDRESS_WRAP);
    device->SetSamplerState(0, D3DSAMP_MAGFILTER,        D3DTEXF_POINT);
    device->SetSamplerState(0, D3DSAMP_MINFILTER,        D3DTEXF_POINT);

    cur_srs = 0;

    //force to default dynamic states
    force_default_dynamic_states();

    return true;
}

bool _gpu_t::present() 
{
    HRESULT hr = device->Present(0, 0, 0, 0);
    if( FAILED(hr) )
    {
        switch( hr )
        {
        case D3DERR_DEVICELOST:                _error_record_ = _gpu_error_device_lost_; break;
        case D3DERR_DRIVERINTERNALERROR:    _error_record_ = _gpu_error_driver_internal_error_; break;
        default:                            _error_record_ = _gpu_error_unknown_; break;
        }
        return false;
    }
    return true;
}

bool _gpu_t::test_cooperative_level() 
{
    HRESULT hr = device->TestCooperativeLevel();
    if( FAILED(hr) )
    {
        switch( hr )
        {
        case D3DERR_DEVICELOST:                _error_record_ = _gpu_error_device_lost_; break;
        case D3DERR_DEVICENOTRESET:            _error_record_ = _gpu_error_device_not_reset_; break;
        case D3DERR_DRIVERINTERNALERROR:    _error_record_ = _gpu_error_driver_internal_error_; break;
        default:                            _error_record_ = _gpu_error_unknown_; break;
        }
        return false;
    }
    return true;
}

//dynamic caps
byte4 _gpu_t::build_valid_render_target_formats(buffer_t* out)
{
    const D3DFORMAT fmt_vec[] = 
    {   
            D3DFMT_R8G8B8                ,
            D3DFMT_A8R8G8B8             ,
            D3DFMT_X8R8G8B8             ,
            D3DFMT_R5G6B5               ,
            D3DFMT_X1R5G5B5             ,
            D3DFMT_A1R5G5B5             ,
            D3DFMT_A4R4G4B4             ,
            D3DFMT_R3G3B2               ,
            D3DFMT_A8R3G3B2             ,
            D3DFMT_X4R4G4B4             ,
            D3DFMT_A2B10G10R10          ,
            D3DFMT_A8B8G8R8             ,
            D3DFMT_X8B8G8R8             ,
            D3DFMT_A2R10G10B10          ,
            D3DFMT_A16B16G16R16         ,
    };
    const byte4 fmt_count = sizeof(fmt_vec) / sizeof(fmt_vec[0]);

    vector<D3DFORMAT>    rt_fmt_vec;
    rt_fmt_vec.reserve(16);

    for(byte4 ifmt = 0; ifmt < fmt_count; ifmt++)
    {
        //it should be a render target
        if(FAILED(d3d->CheckDeviceFormat(ordinal, D3DDEVTYPE_HAL, cur_pp.display_mode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, fmt_vec[ifmt]))) 
            continue;

        //compatible with ds
        if(FAILED(d3d->CheckDepthStencilMatch(ordinal, D3DDEVTYPE_HAL, cur_pp.display_mode.Format, fmt_vec[ifmt], cur_pp.depthstencil_format)))
            continue;

        //multisample should match
        byte4 quality_level_count;
        if(FAILED(d3d->CheckDeviceMultiSampleType(ordinal, D3DDEVTYPE_HAL, fmt_vec[ifmt], cur_pp.windowed, cur_pp.multisample_type, &quality_level_count)))
            continue;

        if(quality_level_count < cur_pp.multisample_quality + 1)
            continue;

        //find one, add it
        rt_fmt_vec.push_back(fmt_vec[ifmt]);
    }

    if(rt_fmt_vec.empty())
        return 0;

    buffer_t buf;
    D3DXCreateBuffer((byte4)rt_fmt_vec.size() * sizeof(D3DFORMAT), &buf);

    memcpy(buf->GetBufferPointer(), &rt_fmt_vec[0], buf->GetBufferSize());
    *out = buf;

    return (byte4)rt_fmt_vec.size();
}

byte4 _gpu_t::build_valid_render_target_texture_formats(buffer_t* out)
{
    const D3DFORMAT fmt_vec[] = 
    {   
            D3DFMT_R8G8B8                ,
            D3DFMT_A8R8G8B8             ,
            D3DFMT_X8R8G8B8             ,
            D3DFMT_R5G6B5               ,
            D3DFMT_X1R5G5B5             ,
            D3DFMT_A1R5G5B5             ,
            D3DFMT_A4R4G4B4             ,
            D3DFMT_R3G3B2               ,
            D3DFMT_A8R3G3B2             ,
            D3DFMT_X4R4G4B4             ,
            D3DFMT_A2B10G10R10          ,
            D3DFMT_A8B8G8R8             ,
            D3DFMT_X8B8G8R8             ,
            D3DFMT_A2R10G10B10          ,
            D3DFMT_A16B16G16R16         ,
    };
    const byte4 fmt_count = sizeof(fmt_vec) / sizeof(fmt_vec[0]);

    vector<D3DFORMAT>    rt_tex_fmt_vec;
    rt_tex_fmt_vec.reserve(16);

    for(byte4 ifmt = 0; ifmt < fmt_count; ifmt++)
    {
        //it should be a render target
        if(FAILED(d3d->CheckDeviceFormat(ordinal, D3DDEVTYPE_HAL, cur_pp.display_mode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, fmt_vec[ifmt]))) 
            continue;

        //compatible with ds
        if(FAILED(d3d->CheckDepthStencilMatch(ordinal, D3DDEVTYPE_HAL, cur_pp.display_mode.Format, fmt_vec[ifmt], cur_pp.depthstencil_format)))
            continue;

        //find one, add it
        rt_tex_fmt_vec.push_back(fmt_vec[ifmt]);
    }

    if( rt_tex_fmt_vec.empty() )
    {
        //ignore depth-stencil
        for( byte4 ifmt = 0; ifmt < fmt_count; ifmt++ )
        {
            //it should be a render target
            if( FAILED(d3d->CheckDeviceFormat(ordinal, D3DDEVTYPE_HAL, cur_pp.display_mode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_TEXTURE, fmt_vec[ifmt])) ) 
                continue;

            //find one, add it
            rt_tex_fmt_vec.push_back( fmt_vec[ifmt] );
        }
    }

    if(rt_tex_fmt_vec.empty())
        return 0;

    buffer_t buf;
    D3DXCreateBuffer((byte4)rt_tex_fmt_vec.size() * sizeof(D3DFORMAT), &buf);

    memcpy(buf->GetBufferPointer(), &rt_tex_fmt_vec[0], buf->GetBufferSize());
    *out = buf;

    return (byte4)rt_tex_fmt_vec.size();
}

byte4 _gpu_t::build_valid_offscr_texture_formats(buffer_t* out)
{
    const D3DFORMAT fmt_vec[] = 
    {   
            D3DFMT_R8G8B8                ,
            D3DFMT_A8R8G8B8             ,
            D3DFMT_X8R8G8B8             ,
            D3DFMT_R5G6B5               ,
            D3DFMT_X1R5G5B5             ,
            D3DFMT_A1R5G5B5             ,
            D3DFMT_A4R4G4B4             ,
            D3DFMT_R3G3B2               ,
            D3DFMT_A8                   ,
            D3DFMT_A8R3G3B2             ,
            D3DFMT_X4R4G4B4             ,
            D3DFMT_A2B10G10R10          ,
            D3DFMT_A8B8G8R8             ,
            D3DFMT_X8B8G8R8             ,
            D3DFMT_A2R10G10B10          ,
            D3DFMT_A16B16G16R16         ,
            D3DFMT_DXT1                    ,
            D3DFMT_DXT2                    ,
            D3DFMT_DXT3                    ,
            D3DFMT_DXT4                    ,
            D3DFMT_DXT5                    ,
    };
    const byte4 fmt_count = sizeof(fmt_vec) / sizeof(fmt_vec[0]);

    vector<D3DFORMAT>    offscr_tex_fmt_vec;
    offscr_tex_fmt_vec.reserve(16);

    for(byte4 ifmt = 0; ifmt < fmt_count; ifmt++)
    {
        //it should be a texture
        if(FAILED(d3d->CheckDeviceFormat(ordinal, D3DDEVTYPE_HAL, cur_pp.display_mode.Format, 0, D3DRTYPE_TEXTURE, fmt_vec[ifmt]))) 
            continue;

        //find one, add it
        offscr_tex_fmt_vec.push_back(fmt_vec[ifmt]);
    }

    if(offscr_tex_fmt_vec.empty())
        return 0;

    buffer_t buf;
    D3DXCreateBuffer((byte4)offscr_tex_fmt_vec.size() * sizeof(D3DFORMAT), &buf);

    memcpy(buf->GetBufferPointer(), &offscr_tex_fmt_vec[0], buf->GetBufferSize());
    *out = buf;

    return (byte4)offscr_tex_fmt_vec.size();
}

byte4 _gpu_t::build_valid_downsampling_target_formats(buffer_t* out)
{
    //rt fmts
    buffer_t rt_fmts_buf;
    byte4 rt_fmt_count = build_valid_render_target_formats(&rt_fmts_buf);
    if(!rt_fmt_count)
        return 0;
    D3DFORMAT* rt_fmt_vec = (D3DFORMAT*)rt_fmts_buf->GetBufferPointer();

    //rt texture fmts
    buffer_t rttex_fmts_buf;
    byte4 rttex_fmt_count = build_valid_render_target_texture_formats(&rttex_fmts_buf);
    if(!rttex_fmt_count)
    {
        rt_fmts_buf->Release();
        return 0;
    }
    D3DFORMAT* rttex_fmt_vec = (D3DFORMAT*)rttex_fmts_buf->GetBufferPointer();

    //loop & check
    vector<D3DFORMAT> valid_dst_fmt_vec;
    for(byte4 irttex = 0; irttex < rttex_fmt_count; irttex++)
    {
        for(byte4 irt = 0; irt < rt_fmt_count; irt++)
        {
            if(FAILED(d3d->CheckDeviceFormatConversion(ordinal, D3DDEVTYPE_HAL, rt_fmt_vec[irt], rttex_fmt_vec[irttex])))
                continue;

            //find one, add it
            valid_dst_fmt_vec.push_back(rttex_fmt_vec[irttex]);
            break;
        }
    }

    rt_fmts_buf->Release();
    rttex_fmts_buf->Release();

    if(valid_dst_fmt_vec.empty())
        return 0;

    buffer_t buf;
    D3DXCreateBuffer((byte4)valid_dst_fmt_vec.size() * sizeof(D3DFORMAT), &buf);
    memcpy(buf->GetBufferPointer(), &valid_dst_fmt_vec[0], buf->GetBufferSize());
    *out = buf;

    return (byte4)valid_dst_fmt_vec.size();
}

byte4 _gpu_t::build_valid_downsampling_source_formats(D3DFORMAT target_format, buffer_t* out)
{
    //rt fmts
    buffer_t rt_fmts_buf;
    byte4 rt_fmt_count = build_valid_render_target_formats(&rt_fmts_buf);
    if(!rt_fmt_count)
        return 0;
    D3DFORMAT* rt_fmt_vec = (D3DFORMAT*)rt_fmts_buf->GetBufferPointer();

    //loop & check
    vector<D3DFORMAT> valid_src_fmt_vec;
    for(byte4 irt = 0; irt < rt_fmt_count; irt++)
    {
        if(FAILED(d3d->CheckDeviceFormatConversion(ordinal, D3DDEVTYPE_HAL, rt_fmt_vec[irt], target_format)))
            continue;

        //find one, add it
        valid_src_fmt_vec.push_back(rt_fmt_vec[irt]);
    }

    rt_fmts_buf->Release();

    if(valid_src_fmt_vec.empty())
        return 0;

    buffer_t buf;
    D3DXCreateBuffer((byte4)valid_src_fmt_vec.size() * sizeof(D3DFORMAT), &buf);
    memcpy(buf->GetBufferPointer(), &valid_src_fmt_vec[0], buf->GetBufferSize());
    *out = buf;

    return (byte4)valid_src_fmt_vec.size();
}

//decl pool
bool _gpu_t::create_vertex_declaration(byte4 fvf, d3ddecl_t* out)
{
    map<byte4, d3ddecl_t>::iterator pdecl = decl_map.find(fvf);
    if(pdecl != decl_map.end())
    {
        pdecl->second->AddRef();
        *out = pdecl->second;
        return true;
    }
    else
    {
        D3DVERTEXELEMENT9 decl_elems[MAX_FVF_DECL_SIZE];
        if(FAILED(D3DXDeclaratorFromFVF(fvf, decl_elems)))
            return false;
        
        d3ddecl_t decl;
        if(FAILED(device->CreateVertexDeclaration(decl_elems, &decl)))
            return false;
        
        decl_map[fvf] = decl;
        decl->AddRef();
        *out = decl;
        return true;
    }
}

//dynamic vertex buffer
void _gpu_t::set_dynamic_vertex_buffer_size(byte4 size)
{
    SAFE_RELEASE(dynvb);
    dynvb_size = size;
    dynvb_used_bytes = 0;
    dynvb_broken = false;
}

void* _gpu_t::lock_dynamic_vertex_buffer(byte4 vertex_count, byte4 stride, byte4* start_vertex, d3dvb_t* vertex_buffer)
{
    //create dynvb lazily
    if( !dynvb && dynvb_size > 0 && !dynvb_broken )
    {
        if(FAILED(device->CreateVertexBuffer(dynvb_size, D3DUSAGE_DYNAMIC|D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &dynvb, 0)))
        {
            //creating dynamic vertex buffer failed, mark it as broken
            dynvb_broken = true;
            return 0;
        }
    }

    //check dynvb
    if(!dynvb)
        return 0;

    //align to a mutliple of 'stride'
    dynvb_used_bytes += ((stride - dynvb_used_bytes % stride) % stride);

    byte4 lock_size = stride * vertex_count;
    
    if( dynvb_used_bytes + lock_size <= dynvb_size )
    {
        //lock with no-overwrite
        void* v;
        if(FAILED(dynvb->Lock(dynvb_used_bytes, lock_size, &v, D3DLOCK_NOOVERWRITE)))
            return 0;
        
        *start_vertex = dynvb_used_bytes / stride;
        dynvb_used_bytes += lock_size;
        *vertex_buffer = dynvb;
        return v;
    }
    else
    {
        //fail if the buffer is not large enough
        if(dynvb_size < lock_size)
            return 0;

        //lock with discard
        void* v;
        if(FAILED(dynvb->Lock(0, 0, &v, D3DLOCK_DISCARD)))
            return 0;

        *start_vertex = 0;
        dynvb_used_bytes = lock_size;
        *vertex_buffer = dynvb;
        return v;
    }
}

void _gpu_t::unlock_dynamic_vertex_buffer()
{
    dynvb->Unlock();
}

//global render states
void _gpu_t::set_view_matrix(const matrix* view)
{
    device->SetTransform(D3DTS_VIEW, view);
    mat_view = *view;
    mat_viewproj = mat_view * mat_proj;
    D3DXMatrixTranspose(&mat_viewproj_transpose, &mat_viewproj);
    if(viewproj_vsconst_reg != -1)
    {
        device->SetVertexShaderConstantF(viewproj_vsconst_reg, (float*)&mat_viewproj_transpose, 4);
    }
    matrix mat_viewport;
    build_viewport_matrix(&mat_viewport, &cur_viewport);
    mat_viewprojviewport = mat_viewproj * mat_viewport;
}

void _gpu_t::set_proj_matrix(const matrix* proj)
{
    device->SetTransform(D3DTS_PROJECTION, proj);
    mat_proj = *proj;
    mat_viewproj = mat_view * mat_proj;
    D3DXMatrixTranspose(&mat_viewproj_transpose, &mat_viewproj);
    if(viewproj_vsconst_reg != -1)
    {
        device->SetVertexShaderConstantF(viewproj_vsconst_reg, (float*)&mat_viewproj_transpose, 4);
    }
    matrix mat_viewport;
    build_viewport_matrix(&mat_viewport, &cur_viewport);
    mat_viewprojviewport = mat_viewproj * mat_viewport;
}

void _gpu_t::set_viewport(const D3DVIEWPORT9* viewport)
{
    device->SetViewport(viewport);
    cur_viewport = *viewport;
    matrix mat_viewport;
    build_viewport_matrix(&mat_viewport, &cur_viewport);
    mat_viewprojviewport = mat_viewproj * mat_viewport;
}

void _gpu_t::map_viewproj_to_vsconst(byte4 reg)
{
    if(viewproj_vsconst_reg != -1)
    {
        //clear original
        float4 v[4];
        v[0] = v[1] = v[2] = v[3] = float4(0, 0, 0, 1);
        device->SetVertexShaderConstantF(viewproj_vsconst_reg, (float*)&v[0], 4);
    }
    //map new one
    viewproj_vsconst_reg = reg;
    if(viewproj_vsconst_reg != -1)
    {
        device->SetVertexShaderConstantF(viewproj_vsconst_reg, (float*)&mat_viewproj_transpose, 4);
    }
}

void _gpu_t::set_global_vsconst(byte4 reg, const float* data, byte4 float4_count)
{
    byte4 old_size = (byte4)global_vsconst_vec.size();
    global_vsconst_vec.resize(old_size + 1);
    global_vsconst_vec[old_size].start_reg = reg;
    global_vsconst_vec[old_size].data.resize(float4_count);
    memcpy(&global_vsconst_vec[old_size].data[0], data, sizeof(float4) * float4_count);
    device->SetVertexShaderConstantF(reg, data, float4_count);
}

//static render states
byte4 _gpu_t::define_static_render_states(const static_render_states_t* in)
{
    byte4 old_size = (byte4)srs_vec.size();
    srs_vec.push_back(*in);
    transition_table.resize(old_size + 1);
    for(byte4 i = 0; i < old_size + 1; i++)
    {
        transition_table[i].resize(old_size + 1);
    }
    for(byte4 i = 0; i < old_size + 1; i++)
    {
        transition_table[i][old_size].init(&srs_vec[i], &srs_vec[old_size]);
    }
    for(byte4 i = 0; i < old_size; i++)
    {
        transition_table[old_size][i].init(&srs_vec[old_size], &srs_vec[i]);
    }
    return old_size;
}

void _gpu_t::set_static_render_states(byte4 id)
{
    transition_table[cur_srs][id].apply(device);
    cur_srs = id;
}

//dynamic states
void _gpu_t::set_software_vertex_processing(bool software)
{
    if(cur_cp.vertex_processing_method == _gpu_vertex_processing_method_mixed_ && cur_drs.software_vertex_processing != software)
    {
        device->SetSoftwareVertexProcessing(software);
        cur_drs.software_vertex_processing = software;
    }
}

void _gpu_t::set_stream_source(d3dvb_t vertex_buffer, byte4 stride)
{
    if(cur_drs.vertex_buffer != vertex_buffer || cur_drs.stride != stride)
    {
        device->SetStreamSource(0, vertex_buffer, 0, stride);
        cur_drs.vertex_buffer = vertex_buffer;
        cur_drs.stride = stride;
    }
}

void _gpu_t::set_indices(d3dib_t index_buffer)
{
    if(cur_drs.index_buffer != index_buffer)
    {
        device->SetIndices(index_buffer);
        cur_drs.index_buffer = index_buffer;
    }
}

void _gpu_t::set_fvf(byte4 fvf)
{
    if(!cur_drs.use_fvf || cur_drs.fvf != fvf)
    {
        device->SetFVF(fvf);
        cur_drs.use_fvf = true;
        cur_drs.fvf = fvf;
    }
}

void _gpu_t::set_decl(d3ddecl_t decl)
{
    if(cur_drs.use_fvf || cur_drs.decl != decl)
    {
        device->SetVertexDeclaration(decl);
        cur_drs.use_fvf = false;
        cur_drs.decl = decl;
    }
}

void _gpu_t::set_vertex_shader(d3dvs_t vertex_shader)
{
    if(cur_drs.vertex_shader != vertex_shader)
    {
        device->SetVertexShader(vertex_shader);
        cur_drs.vertex_shader = vertex_shader;
    }
}

void _gpu_t::set_vertex_shader_constants(byte4 start_register, const float* data, byte4 float4_count)
{
    device->SetVertexShaderConstantF(start_register, data, float4_count);
}

void _gpu_t::set_vertex_blend(D3DVERTEXBLENDFLAGS vertex_blend)
{
    if(cur_drs.vertex_blend != vertex_blend)
    {
        device->SetRenderState(D3DRS_VERTEXBLEND, vertex_blend);
        cur_drs.vertex_blend = vertex_blend;
    }
}

void _gpu_t::set_indexed_vertex_blend_enable(bool enable)
{
    if(cur_drs.indexed_vertex_blend_enable != enable)
    {
        device->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, enable);
        cur_drs.indexed_vertex_blend_enable = enable;
    }
}

void _gpu_t::set_world_matrix(byte4 index, const matrix* world_matrix)
{
    device->SetTransform(D3DTS_WORLDMATRIX(index), world_matrix);
}

void _gpu_t::set_texture(d3dtexture_t texture)
{
    if(cur_drs.texture != texture)
    {
        device->SetTexture(0, texture);
        cur_drs.texture = texture;
    }
}

void _gpu_t::set_texture_factor(byte4 factor)
{
    if(cur_drs.texture_factor != factor)
    {
        device->SetRenderState(D3DRS_TEXTUREFACTOR, factor);
        cur_drs.texture_factor = factor;
    }
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值